|
|
@@ -5,6 +5,7 @@
|
|
|
#include <iostream>
|
|
|
#include <memory>
|
|
|
#include <regex>
|
|
|
+#include <sstream>
|
|
|
#include <string>
|
|
|
#include <thread>
|
|
|
|
|
|
@@ -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] <filename>\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] <filename>\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<char>(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<Service::AM::AppletId>(std::stoul(sub));
|
|
|
+ std::getline(stream, sub, ',');
|
|
|
+ load_parameters.applet_type = static_cast<Service::AM::AppletType>(std::stoi(sub));
|
|
|
+ std::getline(stream, sub, ',');
|
|
|
+ load_parameters.launch_type = static_cast<Service::AM::LaunchType>(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<u32>(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<u32>(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<u64>(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) {
|