add dump options, allow for gamecard menu to be accessed without install enabled.

This commit is contained in:
ITotalJustice
2025-05-21 19:52:22 +01:00
parent 52b166932d
commit a91550174a
5 changed files with 91 additions and 17 deletions

View File

@@ -115,6 +115,7 @@ public:
static void DisplayMiscOptions(bool left_side = true);
static void DisplayAdvancedOptions(bool left_side = true);
static void DisplayInstallOptions(bool left_side = true);
static void DisplayDumpOptions(bool left_side = true);
void Draw();
void Update();
@@ -252,6 +253,12 @@ public:
option::OptionBool m_lower_master_key{INI_SECTION, "lower_master_key", false};
option::OptionBool m_lower_system_version{INI_SECTION, "lower_system_version", false};
// dump options
option::OptionBool m_dump_app_folder{"dump", "app_folder", true};
option::OptionBool m_dump_append_folder_with_xci{"dump", "append_folder_with_xci", true};
option::OptionBool m_dump_trim_xci{"dump", "trim_xci", false};
option::OptionBool m_dump_usb_transfer_stream{"dump", "usb_transfer_stream", true};
// todo: move this into it's own menu
option::OptionLong m_text_scroll_speed{"accessibility", "text_scroll_speed", 1}; // normal

View File

@@ -1590,6 +1590,10 @@ void App::DisplayAdvancedOptions(bool left_side) {
options->Add(std::make_shared<ui::SidebarEntryCallback>("Install options"_i18n, [left_side](){
App::DisplayInstallOptions(left_side);
}));
options->Add(std::make_shared<ui::SidebarEntryCallback>("Dump options"_i18n, [left_side](){
App::DisplayDumpOptions(left_side);
}));
}
void App::DisplayInstallOptions(bool left_side) {
@@ -1681,6 +1685,27 @@ void App::DisplayInstallOptions(bool left_side) {
}));
}
void App::DisplayDumpOptions(bool left_side) {
auto options = std::make_shared<ui::Sidebar>("Dump Options"_i18n, left_side ? ui::Sidebar::Side::LEFT : ui::Sidebar::Side::RIGHT);
ON_SCOPE_EXIT(App::Push(options));
options->Add(std::make_shared<ui::SidebarEntryBool>("Created nested folder"_i18n, App::GetApp()->m_dump_app_folder.Get(), [](bool& enable){
App::GetApp()->m_dump_app_folder.Set(enable);
}));
options->Add(std::make_shared<ui::SidebarEntryBool>("Append folder with .xci"_i18n, App::GetApp()->m_dump_append_folder_with_xci.Get(), [](bool& enable){
App::GetApp()->m_dump_append_folder_with_xci.Set(enable);
}));
options->Add(std::make_shared<ui::SidebarEntryBool>("Trim XCI"_i18n, App::GetApp()->m_dump_trim_xci.Get(), [](bool& enable){
App::GetApp()->m_dump_trim_xci.Set(enable);
}));
options->Add(std::make_shared<ui::SidebarEntryBool>("Multi-threaded USB transfer"_i18n, App::GetApp()->m_dump_usb_transfer_stream.Get(), [](bool& enable){
App::GetApp()->m_dump_usb_transfer_stream.Set(enable);
}));
}
App::~App() {
log_write("starting to exit\n");

View File

@@ -410,7 +410,11 @@ Result DumpNspToUsbS2S(ProgressBox* pbox, std::span<NspEntry> entries) {
while (!pbox->ShouldExit()) {
if (R_SUCCEEDED(usb->IsUsbConnected(timeout))) {
pbox->NewTransfer("USB connected, sending file list");
const u8 flags = usb::tinfoil::USBFlag_STREAM;
u8 flags = usb::tinfoil::USBFlag_NONE;
if (App::GetApp()->m_dump_usb_transfer_stream.Get()) {
flags |= usb::tinfoil::USBFlag_STREAM;
}
if (R_SUCCEEDED(usb->WaitForConnection(timeout, flags, file_list))) {
pbox->NewTransfer("Sent file list, waiting for command...");
@@ -740,7 +744,12 @@ auto BuildNspPath(const Entry& e, const NsApplicationContentMetaStatus& status)
}
fs::FsPath path;
if (App::GetApp()->m_dump_app_folder.Get()) {
std::snprintf(path, sizeof(path), "%s/%s %s[%016lX][v%u][%s].nsp", name_buf.s, name_buf.s, version, status.application_id, status.version, ncm::GetMetaTypeShortStr(status.meta_type));
} else {
std::snprintf(path, sizeof(path), "%s %s[%016lX][v%u][%s].nsp", name_buf.s, version, status.application_id, status.version, ncm::GetMetaTypeShortStr(status.meta_type));
}
return path;
}
@@ -1117,6 +1126,10 @@ Menu::Menu() : grid::Menu{"Games"_i18n} {
}, true));
}, true));
options->Add(std::make_shared<SidebarEntryCallback>("Dump options"_i18n, [this](){
App::DisplayDumpOptions(false);
}));
// completely deletes the application record and all data.
options->Add(std::make_shared<SidebarEntryCallback>("Delete"_i18n, [this](){
const auto buf = "Are you sure you want to delete "_i18n + m_entries[m_index].GetName() + "?";

View File

@@ -2,6 +2,7 @@
#include "ui/nvg_util.hpp"
#include "ui/sidebar.hpp"
#include "ui/popup_list.hpp"
#include "ui/option_box.hpp"
#include "yati/yati.hpp"
#include "yati/nx/nca.hpp"
@@ -150,8 +151,16 @@ auto BuildFilePath(DumpFileType type, std::span<const ApplicationEntry> entries)
// builds path suiteable for file dumps.
auto BuildFullDumpPath(DumpFileType type, std::span<const ApplicationEntry> entries) -> fs::FsPath {
const auto base_path = BuildXciBasePath(entries);
if (App::GetApp()->m_dump_app_folder.Get()) {
if (App::GetApp()->m_dump_append_folder_with_xci.Get()) {
return base_path + ".xci/" + base_path + GetDumpTypeStr(type);
} else {
return base_path + "/" + base_path + GetDumpTypeStr(type);
}
} else {
return base_path + GetDumpTypeStr(type);
}
}
// @Gc is the mount point, S is for secure partion, the remaining is the
// the gamecard handle value in lower-case hex.
@@ -397,7 +406,11 @@ Result DumpNspToUsbS2S(ProgressBox* pbox, std::span<const fs::FsPath> paths, Xci
while (!pbox->ShouldExit()) {
if (R_SUCCEEDED(usb->IsUsbConnected(timeout))) {
pbox->NewTransfer("USB connected, sending file list");
const u8 flags = usb::tinfoil::USBFlag_STREAM;
u8 flags = usb::tinfoil::USBFlag_NONE;
if (App::GetApp()->m_dump_usb_transfer_stream.Get()) {
flags |= usb::tinfoil::USBFlag_STREAM;
}
if (R_SUCCEEDED(usb->WaitForConnection(timeout, flags, file_list))) {
pbox->NewTransfer("Sent file list, waiting for command...");
@@ -636,7 +649,16 @@ Menu::Menu() : MenuBase{"GameCard"_i18n} {
SetPop();
}}),
std::make_pair(Button::X, Action{"Options"_i18n, [this](){
auto options = std::make_shared<Sidebar>("Game Options"_i18n, Sidebar::Side::RIGHT);
ON_SCOPE_EXIT(App::Push(options));
options->Add(std::make_shared<SidebarEntryCallback>("Install options"_i18n, [this](){
App::DisplayInstallOptions(false);
}));
options->Add(std::make_shared<SidebarEntryCallback>("Dump options"_i18n, [this](){
App::DisplayDumpOptions(false);
}));
}})
);
@@ -875,6 +897,13 @@ Result Menu::GcMount() {
}
if (m_option_index == 0) {
if (!App::GetInstallEnable()) {
App::Push(std::make_shared<ui::OptionBox>(
"Install disabled...\n"
"Please enable installing via the install options."_i18n,
"OK"_i18n
));
} else {
App::Push(std::make_shared<ui::ProgressBox>(m_icon, "Installing "_i18n, m_entries[m_entry_index].lang_entry.name, [this](auto pbox) -> Result {
auto source = std::make_shared<GcSource>(m_entries[m_entry_index], m_fs.get());
return yati::InstallFromCollections(pbox, source, source->m_collections, source->m_config);
@@ -885,6 +914,7 @@ Result Menu::GcMount() {
App::Notify("Gc install success!"_i18n);
}
}));
}
} else {
auto options = std::make_shared<Sidebar>("Select content to dump"_i18n, Sidebar::Side::RIGHT);
ON_SCOPE_EXIT(App::Push(options));
@@ -1206,8 +1236,7 @@ void Menu::DumpGames(u32 flags) {
std::vector<fs::FsPath> paths;
if (flags & DumpFileFlag_XCI) {
// todo: add config support for full and trimmed.
if (1) {
if (App::GetApp()->m_dump_trim_xci.Get()) {
entry.xci_size = m_storage_trimmed_size;
paths.emplace_back(BuildFullDumpPath(DumpFileType_TrimmedXCI, m_entries));
} else {

View File

@@ -43,7 +43,7 @@ const MiscMenuEntry MISC_MENU_ENTRIES[] = {
{ .name = "GitHub", .title = "GitHub", .func = MiscMenuFuncGenerator<ui::menu::gh::Menu>, .flag = MiscMenuFlag_Shortcut },
{ .name = "FTP", .title = "FTP Install", .func = MiscMenuFuncGenerator<ui::menu::ftp::Menu>, .flag = MiscMenuFlag_Install },
{ .name = "USB", .title = "USB Install", .func = MiscMenuFuncGenerator<ui::menu::usb::Menu>, .flag = MiscMenuFlag_Install },
{ .name = "GameCard", .title = "GameCard Install", .func = MiscMenuFuncGenerator<ui::menu::gc::Menu>, .flag = MiscMenuFlag_Shortcut|MiscMenuFlag_Install },
{ .name = "GameCard", .title = "GameCard", .func = MiscMenuFuncGenerator<ui::menu::gc::Menu>, .flag = MiscMenuFlag_Shortcut },
{ .name = "IRS", .title = "IRS (Infrared Joycon Camera)", .func = MiscMenuFuncGenerator<ui::menu::irs::Menu>, .flag = MiscMenuFlag_Shortcut },
};