diff --git a/src/core/hle/service/am/am_types.h b/src/core/hle/service/am/am_types.h index beb52b74dd..1e150f02bf 100644 --- a/src/core/hle/service/am/am_types.h +++ b/src/core/hle/service/am/am_types.h @@ -94,7 +94,9 @@ enum class AppletId : u32 { LoginShare = 0x18, WebAuth = 0x19, MyPage = 0x1A, - Lhub = 0x35 + Lhub = 0x35, + // Homebrew -- uses same ProgramId as qlaunch + UlauncherUmenu = 0xF000'0000, }; enum class AppletProgramId : u64 { diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp index 8a6dc2d033..badf776082 100644 --- a/src/core/hle/service/am/applet_manager.cpp +++ b/src/core/hle/service/am/applet_manager.cpp @@ -24,6 +24,20 @@ namespace Service::AM { namespace { +constexpr size_t NroPathSize = 512; +constexpr size_t NroArgvSize = 2048; +constexpr size_t MenuCaptionSize = 1024; +struct UloaderTargetInput { + u32 magic; + bool target_once; + bool is_auto_game_recording; + std::array unused; + std::array nro_path; + std::array nro_argv; + std::array menu_caption; +}; +static_assert(sizeof(UloaderTargetInput) == 3592); + constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA; struct LaunchParameterAccountPreselectedUser { @@ -121,6 +135,44 @@ void PushInShowController(Core::System& system, AppletStorageChannel& channel) { channel.Push(std::make_shared(system, std::move(user_args_data))); } +void PushInShowUlauncherUmenu(Core::System& system, AppletStorageChannel& channel) { + typedef std::array AccountUid; + const CommonArguments common_args = { + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = 2, + .theme_color = ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + struct UmenuInput { + AccountUid selected_user; + UloaderTargetInput suspended_hb_target_ipt; // Set if homebrew (launched as an application) is currently suspended + u64 suspended_app_id; // Set if any normal application is suspended + std::array last_menu_fs_path; //FS_MAX_PATH + std::array last_menu_path; + u32 last_menu_index; + bool reload_theme_cache; + bool warned_about_outdated_theme; + u32 last_added_app_count; + u32 last_deleted_app_count; + u32 in_verify_app_count; + } user_args = {}; + static_assert(sizeof(UmenuInput) == 5176); + + auto const user = system.GetProfileManager().GetUser(0); + user_args.selected_user[0] = user->uuid[0]; + user_args.selected_user[1] = user->uuid[1]; + user_args.warned_about_outdated_theme = true; + + std::vector common_args_data(sizeof(common_args)); + std::vector user_args_data(sizeof(user_args)); + std::memcpy(common_args_data.data(), std::addressof(common_args), sizeof(common_args)); + std::memcpy(user_args_data.data(), std::addressof(user_args), sizeof(user_args)); + channel.Push(std::make_shared(system, std::move(common_args_data))); + channel.Push(std::make_shared(system, std::move(user_args_data))); +} + void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) { const CommonArguments arguments{ .arguments_version = CommonArgumentVersion::Version3, @@ -295,55 +347,15 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) { // Or ulaunch initialization where we push parameters willingly! if (params.launch_type == LaunchType::ApplicationInitiated) { applet->user_channel_launch_parameter.swap(m_system.GetUserChannel()); - } else if (params.launch_type == LaunchType::FrontendUlaunchInitiated - || params.launch_type == LaunchType::FrontendUmenuInitiated) { - constexpr size_t NroPathSize = 512; - constexpr size_t NroArgvSize = 2048; - constexpr size_t MenuCaptionSize = 1024; - struct UloaderTargetInput { - u32 magic; - bool target_once; - bool is_auto_game_recording; - std::array unused; - std::array nro_path; - std::array nro_argv; - std::array menu_caption; - }; - static_assert(sizeof(UloaderTargetInput) == 3592); - - if (params.launch_type == LaunchType::FrontendUlaunchInitiated) { - UloaderTargetInput target_ipt = {}; - target_ipt.magic = 0x49444C55; // "ULDI" - target_ipt.nro_path = {"sdmc:/hbmenu.nro"}; - target_ipt.menu_caption = {"Loaded by uLoader v1.2.4 - uLaunch's custom hbloader replacement ;)"}; - - std::vector v(sizeof(target_ipt)); - std::memcpy(v.data(), std::addressof(target_ipt), sizeof(target_ipt)); - applet->user_channel_launch_parameter.clear(); - applet->user_channel_launch_parameter.push_back(std::move(v)); - } else { - typedef u64 AccountUid; - struct UmenuInput { - AccountUid selected_user; - UloaderTargetInput suspended_hb_target_ipt; // Set if homebrew (launched as an application) is currently suspended - u64 suspended_app_id; // Set if any normal application is suspended - std::array last_menu_fs_path; //FS_MAX_PATH - std::array last_menu_path; - u32 last_menu_index; - bool reload_theme_cache; - bool warned_about_outdated_theme; - u32 last_added_app_count; - u32 last_deleted_app_count; - u32 in_verify_app_count; - }; - - UmenuInput target_umenu_ipt = {}; - - std::vector v(sizeof(target_umenu_ipt)); - std::memcpy(v.data(), std::addressof(target_umenu_ipt), sizeof(target_umenu_ipt)); - applet->user_channel_launch_parameter.clear(); - applet->user_channel_launch_parameter.push_back(std::move(v)); - } + } else if (params.launch_type == LaunchType::FrontendUlaunchInitiated) { + UloaderTargetInput target_ipt = {}; + target_ipt.magic = 0x49444C55; // "ULDI" + target_ipt.nro_path = {"sdmc:/hbmenu.nro"}; + target_ipt.menu_caption = {"Loaded by uLoader v1.2.4 - uLaunch's custom hbloader replacement ;)"}; + std::vector v(sizeof(target_ipt)); + std::memcpy(v.data(), std::addressof(target_ipt), sizeof(target_ipt)); + applet->user_channel_launch_parameter.clear(); + applet->user_channel_launch_parameter.push_back(std::move(v)); } // TODO: Read whether we need a preselected user from NACP? @@ -385,6 +397,9 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) { case AppletId::Controller: PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet)); break; + case AppletId::UlauncherUmenu: + PushInShowUlauncherUmenu(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; default: break; } 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 3de5740237..764264f81b 100644 --- a/src/core/hle/service/am/service/library_applet_creator.cpp +++ b/src/core/hle/service/am/service/library_applet_creator.cpp @@ -55,6 +55,7 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) { case AppletId::OverlayDisplay: return AppletProgramId::OverlayDisplay; case AppletId::QLaunch: + case AppletId::UlauncherUmenu: //reuses same id as Qlaunch return AppletProgramId::QLaunch; case AppletId::Starter: return AppletProgramId::Starter; diff --git a/src/core/hle/service/ulsf/ulsf.cpp b/src/core/hle/service/ulsf/ulsf.cpp index d218511f4a..bff0e8c847 100644 --- a/src/core/hle/service/ulsf/ulsf.cpp +++ b/src/core/hle/service/ulsf/ulsf.cpp @@ -33,6 +33,8 @@ void ULSF_U::GetVersion(HLERequestContext& ctx) { void LoopProcess(Core::System& system) { auto server_manager = std::make_unique(system); server_manager->RegisterNamedService("ulsf:u", std::make_shared(system)); + server_manager->RegisterNamedService("ulsf:p", std::make_shared(system)); + ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index f3ff0eadda..5eb59f51c5 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -516,6 +516,7 @@ MainWindow::MainWindow(bool has_broken_vulkan) bool should_launch_qlaunch = false; bool should_launch_hlaunch = false; bool should_launch_hlaunch_uloader = false; + bool should_launch_umenu = false; bool should_launch_ulaunch = false; bool should_launch_setup = false; bool has_gamepath = false; @@ -563,7 +564,10 @@ MainWindow::MainWindow(bool has_broken_vulkan) } else if (args[i] == QStringLiteral("-hlaunch-uloader")) { should_launch_hlaunch_uloader = true; } else if (args[i] == QStringLiteral("-ulaunch")) { - should_launch_ulaunch = true; + //should_launch_ulaunch = true; + should_launch_umenu = true; + } else if (args[i] == QStringLiteral("-umenu")) { + should_launch_umenu = true; } else if (args[i] == QStringLiteral("-setup")) { should_launch_setup = true; } else { @@ -595,10 +599,14 @@ MainWindow::MainWindow(bool has_broken_vulkan) params.launch_type = Service::AM::LaunchType::FrontendUlaunchInitiated; BootGame(QString::fromStdString(path), params); } else if (should_launch_ulaunch) { + std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir); + auto const path = (sd_dir / "ulaunch" / "bin" / "uSystem" / "exefs.nsp").string(); + BootGame(QString::fromStdString(path), ApplicationAppletParameters()); + } else if (should_launch_umenu) { std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir); auto const path = (sd_dir / "ulaunch" / "bin" / "uMenu" / "main").string(); - auto const program_id = 0x0100000000010000; - auto params = LibraryAppletParameters(u64(program_id), Service::AM::AppletId::Cabinet); + auto const program_id = 0x010000000000FFFF; + auto params = LibraryAppletParameters(program_id, Service::AM::AppletId::UlauncherUmenu); params.launch_type = Service::AM::LaunchType::FrontendUmenuInitiated; BootGame(QString::fromStdString(path), params); }