mirror of
https://git.suyu.dev/suyu/suyu
synced 2025-12-08 13:52:08 -06:00
Compare commits
10 Commits
v0.0.3
...
more-f18-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81959ea8e5 | ||
|
|
6d20086742 | ||
|
|
311cfa231b | ||
|
|
bd101a52a0 | ||
|
|
6d13a5ea2b | ||
|
|
f91107da04 | ||
|
|
3c9732c9d1 | ||
|
|
5f56ba2af6 | ||
|
|
96db423b41 | ||
|
|
5002fde374 |
@@ -6,7 +6,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
**Note**: We do not support or condone piracy in any form. In order to use suyu, you'll need keys from your real Switch system, and games which you have legally obtained and paid for. We do not intend to make money or profit from this project.
|
||||
|
||||
We're in need of developers. Please join our Matrix below if you want to contribute!
|
||||
We're in need of developers. Please join our Discord server below if you want to contribute!
|
||||
This repo is based on Yuzu EA 4176.
|
||||
|
||||
<hr />
|
||||
@@ -25,7 +25,7 @@ It is written in C++ with portability in mind, and we're actively working on bui
|
||||
</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://chat.suyu.dev">Matrix</a> |
|
||||
<a href="https://discord.gg/suyu">Discord</a> |
|
||||
<a href="#status">Status</a> |
|
||||
<a href="#development">Development</a> |
|
||||
<a href="#downloads">Downloads</a> |
|
||||
@@ -48,7 +48,7 @@ We currently have builds over at the [Releases](https://git.suyu.dev/suyu/suyu/r
|
||||
|
||||
This project is completely free and open source, and anyone can contribute to help improve suyu.
|
||||
|
||||
Most of the development happens on GitLab. For development discussion, please join us on [Matrix](https://chat.suyu.dev).
|
||||
Most of the development happens on GitLab. For development discussion, please join us on [Discord](https://discord.gg/suyu).
|
||||
|
||||
If you want to contribute, please take a look at the [Contributor's Guide](https://git.suyu.dev/suyu/suyu/wiki/Contributing) and [Developer Information](https://git.suyu.dev/suyu/suyu/wiki/Developer-Information).
|
||||
You can also contact any of the developers on Discord to learn more about the current state of suyu.
|
||||
@@ -77,7 +77,7 @@ We have official builds [here.](https://git.suyu.dev/suyu/suyu/releases) If any
|
||||
|
||||
## Support
|
||||
|
||||
If you have any questions, don't hesitate to ask us on [Matrix](https://chat.suyu.dev). We don't bite!
|
||||
If you have any questions, don't hesitate to ask us on [Discord](https://discord.gg/suyu). We don't bite!
|
||||
|
||||
|
||||
## License
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Modified by palfaiate on <2024/03/07>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -175,8 +175,9 @@ constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission per
|
||||
return static_cast<KMemoryPermission>(
|
||||
(static_cast<KMemoryPermission>(perm) & KMemoryPermission::UserMask) |
|
||||
KMemoryPermission::KernelRead |
|
||||
((static_cast<KMemoryPermission>(perm) & KMemoryPermission::UserWrite)
|
||||
<< KMemoryPermission::KernelShift) |
|
||||
((static_cast<KMemoryPermission>(perm) & Svc::MemoryPermission::UserWrite)
|
||||
? KMemoryPermission::KernelWrite
|
||||
: KMemoryPermission::None) |
|
||||
(perm == Svc::MemoryPermission::None ? KMemoryPermission::NotMapped
|
||||
: KMemoryPermission::None));
|
||||
}
|
||||
|
||||
@@ -1594,7 +1594,7 @@ size_t KPageTableBase::GetAliasCodeDataSize() const {
|
||||
}
|
||||
|
||||
Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
|
||||
size_t num_pages, KMemoryPermission perm) {
|
||||
size_t num_pages, KPageProperties& perm) {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
// Create a page group to hold the pages we allocate.
|
||||
@@ -1615,7 +1615,6 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
|
||||
}
|
||||
|
||||
// Map the pages.
|
||||
const KPageProperties properties = {perm, false, false, DisableMergeAttribute::None};
|
||||
R_RETURN(this->Operate(page_list, address, num_pages, pg, properties, OperationType::MapGroup,
|
||||
false));
|
||||
}
|
||||
@@ -2749,12 +2748,12 @@ Result KPageTableBase::MapPages(KProcessAddress* out_addr, size_t num_pages, siz
|
||||
KScopedPageTableUpdater updater(this);
|
||||
|
||||
// Perform mapping operation.
|
||||
KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
|
||||
if (is_pa_valid) {
|
||||
const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
|
||||
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, phys_addr, true, properties,
|
||||
OperationType::Map, false));
|
||||
} else {
|
||||
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, perm));
|
||||
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, properties));
|
||||
}
|
||||
|
||||
// Update the blocks.
|
||||
@@ -2793,7 +2792,8 @@ Result KPageTableBase::MapPages(KProcessAddress address, size_t num_pages, KMemo
|
||||
KScopedPageTableUpdater updater(this);
|
||||
|
||||
// Map the pages.
|
||||
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, perm));
|
||||
KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
|
||||
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, properties));
|
||||
|
||||
// Update the blocks.
|
||||
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm,
|
||||
|
||||
@@ -441,7 +441,7 @@ private:
|
||||
Svc::MemoryState state) const;
|
||||
|
||||
Result AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
|
||||
size_t num_pages, KMemoryPermission perm);
|
||||
size_t num_pages, KPageProperties& perm);
|
||||
Result MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address,
|
||||
const KPageGroup& pg, const KPageProperties properties, bool reuse_ll);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Modified by palfaiate on <2024/03/07>
|
||||
// Reverted palfaiate's changes on <2024/03/25> -Nine-Ball
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
@@ -581,9 +580,6 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
|
||||
remove_menu->addSeparator();
|
||||
QAction* remove_shader_cache = remove_menu->addAction(tr("Remove All Pipeline Caches"));
|
||||
QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents"));
|
||||
QMenu* dump_romfs_menu = context_menu.addMenu(tr("Dump RomFS"));
|
||||
QAction* dump_romfs = dump_romfs_menu->addAction(tr("Dump RomFS"));
|
||||
QAction* dump_romfs_sdmc = dump_romfs_menu->addAction(tr("Dump RomFS to SDMC"));
|
||||
QAction* verify_integrity = context_menu.addAction(tr("Verify Integrity"));
|
||||
QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
|
||||
QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
|
||||
@@ -651,12 +647,6 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
|
||||
connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] {
|
||||
emit RemoveFileRequested(program_id, GameListRemoveTarget::CacheStorage, path);
|
||||
});
|
||||
connect(dump_romfs, &QAction::triggered, [this, program_id, path]() {
|
||||
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal);
|
||||
});
|
||||
connect(dump_romfs_sdmc, &QAction::triggered, [this, program_id, path]() {
|
||||
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::SDMC);
|
||||
});
|
||||
connect(verify_integrity, &QAction::triggered,
|
||||
[this, path]() { emit VerifyIntegrityRequested(path); });
|
||||
connect(copy_tid, &QAction::triggered,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Modified by palfaiate on <2024/03/07>
|
||||
// Reverted palfaiate's changes on <2024/03/25> -Nine-Ball
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -53,11 +52,6 @@ enum class GameListRemoveTarget {
|
||||
CacheStorage,
|
||||
};
|
||||
|
||||
enum class DumpRomFSTarget {
|
||||
Normal,
|
||||
SDMC,
|
||||
};
|
||||
|
||||
enum class GameListShortcutTarget {
|
||||
Desktop,
|
||||
Applications,
|
||||
@@ -119,7 +113,6 @@ signals:
|
||||
void RemoveFileRequested(u64 program_id, GameListRemoveTarget target,
|
||||
const std::string& game_path);
|
||||
void RemovePlayTimeRequested(u64 program_id);
|
||||
void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
|
||||
void VerifyIntegrityRequested(const std::string& game_path);
|
||||
void CopyTIDRequested(u64 program_id);
|
||||
void CreateShortcut(u64 program_id, const std::string& game_path,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Modified by palfaiate on <2024/03/07>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <clocale>
|
||||
#include <cmath>
|
||||
@@ -53,18 +55,6 @@
|
||||
#include "suyu/multiplayer/state.h"
|
||||
#include "suyu/util/controller_navigation.h"
|
||||
|
||||
// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
|
||||
static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper(
|
||||
const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::OpenMode mode) {
|
||||
return vfs->CreateDirectory(path, mode);
|
||||
}
|
||||
|
||||
// Overloaded function, also removed by palafiate
|
||||
static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::VirtualDir& dir,
|
||||
const std::string& path) {
|
||||
return dir->CreateFile(path);
|
||||
}
|
||||
|
||||
#include <fmt/ostream.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
@@ -1475,7 +1465,6 @@ void GMainWindow::ConnectWidgetEvents() {
|
||||
connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile);
|
||||
connect(game_list, &GameList::RemovePlayTimeRequested, this,
|
||||
&GMainWindow::OnGameListRemovePlayTimeData);
|
||||
connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS);
|
||||
connect(game_list, &GameList::VerifyIntegrityRequested, this,
|
||||
&GMainWindow::OnGameListVerifyIntegrity);
|
||||
connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
|
||||
@@ -2380,68 +2369,6 @@ void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path));
|
||||
}
|
||||
|
||||
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 (!QtRawCopy(file, out))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& dir : src->GetSubdirectories()) {
|
||||
const auto out = dest->CreateSubdirectory(dir->GetName());
|
||||
if (!RomFSRawCopy(total_size, read_size, dialog, dir, out, full))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const {
|
||||
switch (type) {
|
||||
case InstalledEntryType::Game:
|
||||
@@ -2683,121 +2610,6 @@ void GMainWindow::RemoveCacheStorage(u64 program_id) {
|
||||
Common::FS::RemoveDirRecursively(path);
|
||||
}
|
||||
|
||||
void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path,
|
||||
DumpRomFSTarget target) {
|
||||
const auto failed = [this] {
|
||||
QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
|
||||
tr("There was an error copying the RomFS files or the user "
|
||||
"cancelled the operation."));
|
||||
};
|
||||
|
||||
const auto loader =
|
||||
Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read));
|
||||
if (loader == nullptr) {
|
||||
failed();
|
||||
return;
|
||||
}
|
||||
|
||||
FileSys::VirtualFile packed_update_raw{};
|
||||
loader->ReadUpdateRaw(packed_update_raw);
|
||||
|
||||
const auto& installed = system->GetContentProvider();
|
||||
|
||||
u64 title_id{};
|
||||
u8 raw_type{};
|
||||
if (!SelectRomFSDumpTarget(installed, program_id, &title_id, &raw_type)) {
|
||||
failed();
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
const auto dump_dir =
|
||||
target == DumpRomFSTarget::Normal
|
||||
? Common::FS::GetSuyuPath(Common::FS::SuyuPath::DumpDir)
|
||||
: Common::FS::GetSuyuPath(Common::FS::SuyuPath::SDMCDir) / "atmosphere" / "contents";
|
||||
const auto romfs_dir = fmt::format("{:016X}/romfs", title_id);
|
||||
|
||||
const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir);
|
||||
|
||||
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::OpenMode::ReadWrite);
|
||||
|
||||
if (out == nullptr) {
|
||||
failed();
|
||||
vfs->DeleteDirectory(path);
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
const QStringList selections{tr("Full"), tr("Skeleton")};
|
||||
const auto res = QInputDialog::getItem(
|
||||
this, tr("Select RomFS Dump Mode"),
|
||||
tr("Please select the how you would like the RomFS dumped.<br>Full will copy all of the "
|
||||
"files into the new directory while <br>skeleton will only create the directory "
|
||||
"structure."),
|
||||
selections, 0, false, &ok);
|
||||
if (!ok) {
|
||||
failed();
|
||||
vfs->DeleteDirectory(path);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto extracted = FileSys::ExtractRomFS(romfs);
|
||||
if (extracted == nullptr) {
|
||||
failed();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto full = res == selections.constFirst();
|
||||
|
||||
// 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!"),
|
||||
tr("There is not enough free space at %1 to extract the RomFS. Please "
|
||||
"free up space or select a different dump directory at "
|
||||
"Emulation > Configure > System > Filesystem > Dump Root")
|
||||
.arg(QString::fromStdString(path)));
|
||||
return;
|
||||
}
|
||||
|
||||
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(romfs->GetSize(), read_size, progress, extracted, out, full)) {
|
||||
progress.close();
|
||||
QMessageBox::information(this, tr("RomFS Extraction Succeeded!"),
|
||||
tr("The operation completed successfully."));
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(path)));
|
||||
} else {
|
||||
progress.close();
|
||||
failed();
|
||||
vfs->DeleteDirectory(path);
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) {
|
||||
const auto NotImplemented = [this] {
|
||||
QMessageBox::warning(this, tr("Integrity verification couldn't be performed!"),
|
||||
@@ -4868,66 +4680,6 @@ void GMainWindow::SetFirmwareVersion() {
|
||||
firmware_label->setToolTip(QString::fromStdString(display_title));
|
||||
}
|
||||
|
||||
bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id,
|
||||
u64* selected_title_id, u8* selected_content_record_type) {
|
||||
using ContentInfo = std::tuple<u64, FileSys::TitleType, FileSys::ContentRecordType>;
|
||||
boost::container::flat_set<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.insert({entry.title_id, title_type, record_type});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::Program);
|
||||
RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::HtmlDocument);
|
||||
RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::LegalInformation);
|
||||
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, title_type, record_type] : available_title_ids) {
|
||||
const auto hex_title_id = QString::fromStdString(fmt::format("{:X}", title_id));
|
||||
if (record_type == FileSys::ContentRecordType::Program) {
|
||||
list.push_back(QStringLiteral("Program [%1]").arg(hex_title_id));
|
||||
} else if (record_type == FileSys::ContentRecordType::HtmlDocument) {
|
||||
list.push_back(QStringLiteral("HTML document [%1]").arg(hex_title_id));
|
||||
} else if (record_type == FileSys::ContentRecordType::LegalInformation) {
|
||||
list.push_back(QStringLiteral("Legal information [%1]").arg(hex_title_id));
|
||||
} else {
|
||||
list.push_back(
|
||||
QStringLiteral("DLC %1 [%2]").arg(title_id & 0x7FF).arg(hex_title_id));
|
||||
}
|
||||
}
|
||||
|
||||
bool ok;
|
||||
const auto res = QInputDialog::getItem(
|
||||
this, tr("Select RomFS Dump Target"),
|
||||
tr("Please select which RomFS you would like to dump."), list, 0, false, &ok);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
title_index = list.indexOf(res);
|
||||
}
|
||||
|
||||
const auto& [title_id, title_type, record_type] = *available_title_ids.nth(title_index);
|
||||
*selected_title_id = title_id;
|
||||
*selected_content_record_type = static_cast<u8>(record_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GMainWindow::ConfirmClose() {
|
||||
if (emu_thread == nullptr ||
|
||||
UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) {
|
||||
|
||||
@@ -51,7 +51,6 @@ class WaitTreeWidget;
|
||||
enum class GameListOpenTarget;
|
||||
enum class GameListRemoveTarget;
|
||||
enum class GameListShortcutTarget;
|
||||
enum class DumpRomFSTarget;
|
||||
enum class InstalledEntryType;
|
||||
class GameListPlaceholder;
|
||||
|
||||
@@ -348,7 +347,6 @@ private slots:
|
||||
void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target,
|
||||
const std::string& game_path);
|
||||
void OnGameListRemovePlayTimeData(u64 program_id);
|
||||
void OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
|
||||
void OnGameListVerifyIntegrity(const std::string& game_path);
|
||||
void OnGameListCopyTID(u64 program_id);
|
||||
void OnGameListNavigateToGamedbEntry(u64 program_id,
|
||||
|
||||
Reference in New Issue
Block a user