diff --git a/src/core/hle/service/am/service/library_applet_creator.cpp b/src/core/hle/service/am/service/library_applet_creator.cpp index 3ffb03bc97..4048cb8704 100644 --- a/src/core/hle/service/am/service/library_applet_creator.cpp +++ b/src/core/hle/service/am/service/library_applet_creator.cpp @@ -47,6 +47,75 @@ bool ShouldCreateGuestApplet(AppletId applet_id) { return true; } +std::shared_ptr CreateGuestApplet(Core::System& system, + WindowSystem& window_system, + std::shared_ptr caller_applet, + AppletId applet_id, + LibraryAppletMode mode) { + const auto program_id = static_cast(Service::AM::AppletIdToProgramId(applet_id)); + if (program_id == 0) { + // Unknown applet + return {}; + } + + // TODO: enable other versions of applets + enum : u8 { + Firmware1400 = 14, + Firmware1500 = 15, + Firmware1600 = 16, + Firmware1700 = 17, + }; + + auto process = CreateProcess(system, program_id, Firmware1400, Firmware1700); + if (!process) { + // Couldn't initialize the guest process + return {}; + } + + const auto applet = std::make_shared(system, std::move(process), false); + applet->program_id = program_id; + applet->applet_id = applet_id; + applet->type = AppletType::LibraryApplet; + applet->library_applet_mode = mode; + applet->window_visible = mode != LibraryAppletMode::AllForegroundInitiallyHidden; + + auto broker = std::make_shared(system); + applet->caller_applet = caller_applet; + applet->caller_applet_broker = broker; + caller_applet->child_applets.push_back(applet); + + window_system.TrackApplet(applet, false); + + return std::make_shared(system, broker, applet); +} + +std::shared_ptr CreateFrontendApplet(Core::System& system, + WindowSystem& window_system, + std::shared_ptr caller_applet, + AppletId applet_id, + LibraryAppletMode mode) { + const auto program_id = static_cast(Service::AM::AppletIdToProgramId(applet_id)); + + auto process = std::make_unique(system); + auto applet = std::make_shared(system, std::move(process), false); + applet->program_id = program_id; + applet->applet_id = applet_id; + applet->type = AppletType::LibraryApplet; + applet->library_applet_mode = mode; + + auto storage = std::make_shared(system); + applet->caller_applet = caller_applet; + applet->caller_applet_broker = storage; + applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode); + caller_applet->child_applets.push_back(applet); + + window_system.TrackApplet(applet, false); + + return std::make_shared(system, storage, applet); +} + +} // namespace + AppletProgramId AppletIdToProgramId(AppletId applet_id) { switch (applet_id) { case AppletId::OverlayDisplay: @@ -94,79 +163,10 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) { } } -std::shared_ptr CreateGuestApplet(Core::System& system, - WindowSystem& window_system, - std::shared_ptr caller_applet, - AppletId applet_id, - LibraryAppletMode mode) { - const auto program_id = static_cast(AppletIdToProgramId(applet_id)); - if (program_id == 0) { - // Unknown applet - return {}; - } - - // TODO: enable other versions of applets - enum : u8 { - Firmware1400 = 14, - Firmware1500 = 15, - Firmware1600 = 16, - Firmware1700 = 17, - }; - - auto process = CreateProcess(system, program_id, Firmware1400, Firmware1700); - if (!process) { - // Couldn't initialize the guest process - return {}; - } - - const auto applet = std::make_shared(system, std::move(process), false); - applet->program_id = program_id; - applet->applet_id = applet_id; - applet->type = AppletType::LibraryApplet; - applet->library_applet_mode = mode; - applet->window_visible = mode != LibraryAppletMode::AllForegroundInitiallyHidden; - - auto broker = std::make_shared(system); - applet->caller_applet = caller_applet; - applet->caller_applet_broker = broker; - caller_applet->child_applets.push_back(applet); - - window_system.TrackApplet(applet, false); - - return std::make_shared(system, broker, applet); -} - -std::shared_ptr CreateFrontendApplet(Core::System& system, - WindowSystem& window_system, - std::shared_ptr caller_applet, - AppletId applet_id, - LibraryAppletMode mode) { - const auto program_id = static_cast(AppletIdToProgramId(applet_id)); - - auto process = std::make_unique(system); - auto applet = std::make_shared(system, std::move(process), false); - applet->program_id = program_id; - applet->applet_id = applet_id; - applet->type = AppletType::LibraryApplet; - applet->library_applet_mode = mode; - - auto storage = std::make_shared(system); - applet->caller_applet = caller_applet; - applet->caller_applet_broker = storage; - applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode); - caller_applet->child_applets.push_back(applet); - - window_system.TrackApplet(applet, false); - - return std::make_shared(system, storage, applet); -} - -} // namespace - ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr applet, WindowSystem& window_system) - : ServiceFramework{system_, "ILibraryAppletCreator"}, - m_window_system{window_system}, m_applet{std::move(applet)} { + : ServiceFramework{system_, "ILibraryAppletCreator"}, m_window_system{window_system}, + m_applet{std::move(applet)} { static const FunctionInfo functions[] = { {0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"}, {1, nullptr, "TerminateAllLibraryApplets"}, diff --git a/src/core/hle/service/am/service/library_applet_creator.h b/src/core/hle/service/am/service/library_applet_creator.h index a10a769828..80ea6bd1af 100644 --- a/src/core/hle/service/am/service/library_applet_creator.h +++ b/src/core/hle/service/am/service/library_applet_creator.h @@ -35,4 +35,6 @@ private: const std::shared_ptr m_applet; }; +AppletProgramId AppletIdToProgramId(AppletId applet_id); + } // namespace Service::AM diff --git a/src/suyu_cmd/suyu.cpp b/src/suyu_cmd/suyu.cpp index f559c74f5b..5458b0793b 100644 --- a/src/suyu_cmd/suyu.cpp +++ b/src/suyu_cmd/suyu.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -23,9 +24,12 @@ #include "core/core_timing.h" #include "core/cpu_manager.h" #include "core/crypto/key_manager.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/nca_metadata.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/vfs/vfs_real.h" #include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/service/library_applet_creator.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" #include "frontend_common/config.h" @@ -67,17 +71,23 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; #endif static void PrintHelp(const char* argv0) { - std::cout << "Usage: " << argv0 - << " [options] \n" - "-c, --config Load the specified configuration file\n" - "-f, --fullscreen Start in fullscreen mode\n" - "-g, --game File path of the game to load\n" - "-h, --help Display this help and exit\n" - "-m, --multiplayer=nick:password@address:port" - " Nickname, password, address and port for multiplayer\n" - "-p, --program Pass following string as arguments to executable\n" - "-u, --user Select a specific user profile from 0 to 7\n" - "-v, --version Output version information and exit\n"; + std::cout + << "Usage: " << argv0 + << " [options] \n" + "-c, --config Load the specified configuration file\n" + "-f, --fullscreen Start in fullscreen mode\n" + "-g, --game File path of the game to load\n" + "-h, --help Display this help and exit\n" + "-m, --multiplayer=nick:password@address:port" + " Nickname, password, address and port for multiplayer\n" + "-p, --program Pass following string as arguments to executable\n" + "-u, --user Select a specific user profile from 0 to 7\n" + "-v, --version Output version information and exit\n" + "-l, " + "--applet-params=" + "\"program_id,applet_id,applet_type,launch_type,prog_index,prev_prog_index\"\n" + " Numerical parameters for launching an applet. If applet_id\n" + " is 0, then the provided game will launch, if any.\n"; } static void PrintVersion() { @@ -212,6 +222,7 @@ int main(int argc, char** argv) { bool use_multiplayer = false; bool fullscreen = false; + Service::AM::FrontendAppletParameters load_parameters{}; std::string nickname{}; std::string password{}; std::string address{}; @@ -223,6 +234,7 @@ int main(int argc, char** argv) { {"fullscreen", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"game", required_argument, 0, 'g'}, + {"applet-params", required_argument, 0, 'l'}, {"multiplayer", required_argument, 0, 'm'}, {"program", optional_argument, 0, 'p'}, {"user", required_argument, 0, 'u'}, @@ -232,7 +244,7 @@ int main(int argc, char** argv) { }; while (optind < argc) { - int arg = getopt_long(argc, argv, "g:fhvp::c:u:", long_options, &option_index); + int arg = getopt_long(argc, argv, "g:fhvp::c:u:l:", long_options, &option_index); if (arg != -1) { switch (static_cast(arg)) { case 'c': @@ -250,6 +262,27 @@ int main(int argc, char** argv) { filepath = str_arg; break; } + case 'l': { + std::string str_arg(optarg); + str_arg.append(",0"); // FALLBACK: if string is partially completed ("1234,3") + // this will set all those unset to 0. otherwise we get + // all 3s. + std::stringstream stream(str_arg); + std::string sub; + std::getline(stream, sub, ','); + load_parameters.program_id = std::stoull(sub); + std::getline(stream, sub, ','); + load_parameters.applet_id = static_cast(std::stoul(sub)); + std::getline(stream, sub, ','); + load_parameters.applet_type = static_cast(std::stoi(sub)); + std::getline(stream, sub, ','); + load_parameters.launch_type = static_cast(std::stoi(sub)); + std::getline(stream, sub, ','); + load_parameters.program_index = std::stoi(sub); + std::getline(stream, sub, ','); + load_parameters.previous_program_index = std::stoi(sub); + break; + } case 'm': { use_multiplayer = true; const std::string str_arg(optarg); @@ -331,7 +364,7 @@ int main(int argc, char** argv) { Common::ConfigureNvidiaEnvironmentFlags(); - if (filepath.empty()) { + if (filepath.empty() && !static_cast(load_parameters.applet_id)) { LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); return -1; } @@ -367,9 +400,27 @@ int main(int argc, char** argv) { system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); system.GetUserChannel().clear(); - Service::AM::FrontendAppletParameters load_parameters{ - .applet_id = Service::AM::AppletId::Application, - }; + if (static_cast(load_parameters.applet_id)) { + // code below based off of suyu/main.cpp : GMainWindow::OnHomeMenu() + Service::AM::AppletProgramId applet_prog_id = + Service::AM::AppletIdToProgramId(load_parameters.applet_id); + auto sysnand = system.GetFileSystemController().GetSystemNANDContents(); + if (!sysnand) { + LOG_CRITICAL(Frontend, "Failed to load applet: Firmware not installed."); + return -1; + } + + auto user_applet_nca = sysnand->GetEntry(static_cast(applet_prog_id), + FileSys::ContentRecordType::Program); + if (!user_applet_nca) { + LOG_CRITICAL(Frontend, "Failed to load applet: applet cannot be found."); + return -1; + } + if (filepath.empty()) + filepath = user_applet_nca->GetFullPath(); + } else { + load_parameters.applet_id = Service::AM::AppletId::Application; + } const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath, load_parameters)}; switch (load_result) {