summaryrefslogtreecommitdiff
path: root/src/yuzu/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r--src/yuzu/main.cpp210
1 files changed, 132 insertions, 78 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 33c9fd0af..4e435c7e2 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2010,8 +2010,16 @@ bool GMainWindow::OnShutdownBegin() {
emit EmulationStopping();
+ int shutdown_time = 1000;
+
+ if (system->DebuggerEnabled()) {
+ shutdown_time = 0;
+ } else if (system->GetExitLocked()) {
+ shutdown_time = 5000;
+ }
+
shutdown_timer.setSingleShot(true);
- shutdown_timer.start(system->DebuggerEnabled() ? 0 : 5000);
+ shutdown_timer.start(shutdown_time);
connect(&shutdown_timer, &QTimer::timeout, this, &GMainWindow::OnEmulationStopTimeExpired);
connect(emu_thread.get(), &QThread::finished, this, &GMainWindow::OnEmulationStopped);
@@ -2267,40 +2275,62 @@ void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path));
}
-static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) {
- std::size_t out = 0;
-
- for (const auto& subdir : dir->GetSubdirectories()) {
- out += 1 + CalculateRomFSEntrySize(subdir, full);
- }
-
- return out + (full ? dir->GetFiles().size() : 0);
-}
-
-static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src,
- const FileSys::VirtualDir& dest, std::size_t block_size, bool full) {
+static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog,
+ const FileSys::VirtualDir& src, const FileSys::VirtualDir& dest,
+ bool full) {
if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
return false;
if (dialog.wasCanceled())
return false;
+ std::vector<u8> buffer(CopyBufferSize);
+ auto last_timestamp = std::chrono::steady_clock::now();
+
+ const auto QtRawCopy = [&](const FileSys::VirtualFile& src_file,
+ const FileSys::VirtualFile& dest_file) {
+ if (src_file == nullptr || dest_file == nullptr) {
+ return false;
+ }
+ if (!dest_file->Resize(src_file->GetSize())) {
+ return false;
+ }
+
+ for (std::size_t i = 0; i < src_file->GetSize(); i += buffer.size()) {
+ if (dialog.wasCanceled()) {
+ dest_file->Resize(0);
+ return false;
+ }
+
+ using namespace std::literals::chrono_literals;
+ const auto new_timestamp = std::chrono::steady_clock::now();
+
+ if ((new_timestamp - last_timestamp) > 33ms) {
+ last_timestamp = new_timestamp;
+ dialog.setValue(
+ static_cast<int>(std::min(read_size, total_size) * 100 / total_size));
+ QCoreApplication::processEvents();
+ }
+
+ const auto read = src_file->Read(buffer.data(), buffer.size(), i);
+ dest_file->Write(buffer.data(), read, i);
+
+ read_size += read;
+ }
+
+ return true;
+ };
+
if (full) {
for (const auto& file : src->GetFiles()) {
const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName());
- if (!FileSys::VfsRawCopy(file, out, block_size))
- return false;
- dialog.setValue(dialog.value() + 1);
- if (dialog.wasCanceled())
+ if (!QtRawCopy(file, out))
return false;
}
}
for (const auto& dir : src->GetSubdirectories()) {
const auto out = dest->CreateSubdirectory(dir->GetName());
- if (!RomFSRawCopy(dialog, dir, out, block_size, full))
- return false;
- dialog.setValue(dialog.value() + 1);
- if (dialog.wasCanceled())
+ if (!RomFSRawCopy(total_size, read_size, dialog, dir, out, full))
return false;
}
@@ -2573,50 +2603,48 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
return;
}
- FileSys::VirtualFile base_romfs;
- if (loader->ReadRomFS(base_romfs) != Loader::ResultStatus::Success) {
- failed();
- return;
- }
+ FileSys::VirtualFile packed_update_raw{};
+ loader->ReadUpdateRaw(packed_update_raw);
const auto& installed = system->GetContentProvider();
- const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id);
- if (!romfs_title_id) {
+ u64 title_id{};
+ u8 raw_type{};
+ if (!SelectRomFSDumpTarget(installed, program_id, &title_id, &raw_type)) {
failed();
return;
}
- const auto type = *romfs_title_id == program_id ? FileSys::ContentRecordType::Program
- : FileSys::ContentRecordType::Data;
- const auto base_nca = installed.GetEntry(*romfs_title_id, type);
+ const auto type = static_cast<FileSys::ContentRecordType>(raw_type);
+ const auto base_nca = installed.GetEntry(title_id, type);
if (!base_nca) {
failed();
return;
}
+ const FileSys::NCA update_nca{packed_update_raw, nullptr};
+ if (type != FileSys::ContentRecordType::Program ||
+ update_nca.GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS ||
+ update_nca.GetTitleId() != FileSys::GetUpdateTitleID(title_id)) {
+ packed_update_raw = {};
+ }
+
+ const auto base_romfs = base_nca->GetRomFS();
+ if (!base_romfs) {
+ failed();
+ return;
+ }
+
const auto dump_dir =
target == DumpRomFSTarget::Normal
? Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)
: Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "atmosphere" / "contents";
- const auto romfs_dir = fmt::format("{:016X}/romfs", *romfs_title_id);
+ const auto romfs_dir = fmt::format("{:016X}/romfs", title_id);
const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir);
- FileSys::VirtualFile romfs;
-
- if (*romfs_title_id == program_id) {
- const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), installed};
- romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, nullptr, false);
- } else {
- romfs = installed.GetEntry(*romfs_title_id, type)->GetRomFS();
- }
-
- const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);
- if (extracted == nullptr) {
- failed();
- return;
- }
+ const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed};
+ auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false);
const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::Mode::ReadWrite);
@@ -2640,11 +2668,16 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
return;
}
+ const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);
+ if (extracted == nullptr) {
+ failed();
+ return;
+ }
+
const auto full = res == selections.constFirst();
- const auto entry_size = CalculateRomFSEntrySize(extracted, full);
- // The minimum required space is the size of the extracted RomFS + 1 GiB
- const auto minimum_free_space = extracted->GetSize() + 0x40000000;
+ // The expected required space is the size of the RomFS + 1 GiB
+ const auto minimum_free_space = romfs->GetSize() + 0x40000000;
if (full && Common::FS::GetFreeSpaceSize(path) < minimum_free_space) {
QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
@@ -2655,12 +2688,15 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
return;
}
- QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0,
- static_cast<s32>(entry_size), this);
+ QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, 100, this);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(100);
+ progress.setAutoClose(false);
+ progress.setAutoReset(false);
+
+ size_t read_size = 0;
- if (RomFSRawCopy(progress, extracted, out, 0x400000, full)) {
+ if (RomFSRawCopy(romfs->GetSize(), read_size, progress, extracted, out, full)) {
progress.close();
QMessageBox::information(this, tr("RomFS Extraction Succeeded!"),
tr("The operation completed successfully."));
@@ -3261,7 +3297,7 @@ void GMainWindow::OnPauseContinueGame() {
}
void GMainWindow::OnStopGame() {
- if (system->GetExitLock() && !ConfirmForceLockedExit()) {
+ if (system->GetExitLocked() && !ConfirmForceLockedExit()) {
return;
}
@@ -4350,28 +4386,41 @@ bool GMainWindow::CheckSystemArchiveDecryption() {
return mii_nca->GetRomFS().get() != nullptr;
}
-std::optional<u64> GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed,
- u64 program_id) {
- const auto dlc_entries =
- installed.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
- std::vector<FileSys::ContentProviderEntry> dlc_match;
- dlc_match.reserve(dlc_entries.size());
- std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
- [&program_id, &installed](const FileSys::ContentProviderEntry& entry) {
- return FileSys::GetBaseTitleID(entry.title_id) == program_id &&
- installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
- });
-
- std::vector<u64> romfs_tids;
- romfs_tids.push_back(program_id);
- for (const auto& entry : dlc_match) {
- romfs_tids.push_back(entry.title_id);
- }
-
- if (romfs_tids.size() > 1) {
- QStringList list{QStringLiteral("Base")};
- for (std::size_t i = 1; i < romfs_tids.size(); ++i) {
- list.push_back(QStringLiteral("DLC %1").arg(romfs_tids[i] & 0x7FF));
+bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id,
+ u64* selected_title_id, u8* selected_content_record_type) {
+ using ContentInfo = std::pair<FileSys::TitleType, FileSys::ContentRecordType>;
+ boost::container::flat_map<u64, ContentInfo> available_title_ids;
+
+ const auto RetrieveEntries = [&](FileSys::TitleType title_type,
+ FileSys::ContentRecordType record_type) {
+ const auto entries = installed.ListEntriesFilter(title_type, record_type);
+ for (const auto& entry : entries) {
+ if (FileSys::GetBaseTitleID(entry.title_id) == program_id &&
+ installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success) {
+ available_title_ids[entry.title_id] = {title_type, record_type};
+ }
+ }
+ };
+
+ RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::Program);
+ RetrieveEntries(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
+
+ if (available_title_ids.empty()) {
+ return false;
+ }
+
+ size_t title_index = 0;
+
+ if (available_title_ids.size() > 1) {
+ QStringList list;
+ for (auto& [title_id, content_info] : available_title_ids) {
+ const auto hex_title_id = QString::fromStdString(fmt::format("{:X}", title_id));
+ if (content_info.first == FileSys::TitleType::Application) {
+ list.push_back(QStringLiteral("Application [%1]").arg(hex_title_id));
+ } else {
+ list.push_back(
+ QStringLiteral("DLC %1 [%2]").arg(title_id & 0x7FF).arg(hex_title_id));
+ }
}
bool ok;
@@ -4379,13 +4428,16 @@ std::optional<u64> GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProv
this, tr("Select RomFS Dump Target"),
tr("Please select which RomFS you would like to dump."), list, 0, false, &ok);
if (!ok) {
- return {};
+ return false;
}
- return romfs_tids[list.indexOf(res)];
+ title_index = list.indexOf(res);
}
- return program_id;
+ const auto selected_info = available_title_ids.nth(title_index);
+ *selected_title_id = selected_info->first;
+ *selected_content_record_type = static_cast<u8>(selected_info->second.second);
+ return true;
}
bool GMainWindow::ConfirmClose() {
@@ -4515,6 +4567,8 @@ void GMainWindow::RequestGameExit() {
auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
bool has_signalled = false;
+ system->SetExitRequested(true);
+
if (applet_oe != nullptr) {
applet_oe->GetMessageQueue()->RequestExit();
has_signalled = true;