mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-12-02 05:54:18 +01:00
263 lines
7.3 KiB
C++
263 lines
7.3 KiB
C++
|
#include "LaunchSettings.h"
|
||
|
|
||
|
#include "util/helpers/helpers.h"
|
||
|
#include "Cafe/Account/Account.h"
|
||
|
|
||
|
#include "Cafe/OS/libs/coreinit/coreinit.h"
|
||
|
|
||
|
#include "boost/program_options.hpp"
|
||
|
#include <wx/msgdlg.h>
|
||
|
|
||
|
#include "config/ActiveSettings.h"
|
||
|
#include "util/crypto/aes128.h"
|
||
|
|
||
|
#include "Cafe/Filesystem/FST/FST.h"
|
||
|
|
||
|
void requireConsole();
|
||
|
|
||
|
bool LaunchSettings::HandleCommandline(const wchar_t* lpCmdLine)
|
||
|
{
|
||
|
#if BOOST_OS_WINDOWS
|
||
|
const std::vector<std::wstring> args = boost::program_options::split_winmain(lpCmdLine);
|
||
|
return HandleCommandline(args);
|
||
|
#else
|
||
|
cemu_assert_unimplemented();
|
||
|
return false;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
bool LaunchSettings::HandleCommandline(int argc, wchar_t* argv[])
|
||
|
{
|
||
|
std::vector<std::wstring> args;
|
||
|
args.reserve(argc);
|
||
|
for(int i = 0; i < argc; ++i)
|
||
|
{
|
||
|
args.emplace_back(argv[i]);
|
||
|
}
|
||
|
|
||
|
return HandleCommandline(args);
|
||
|
}
|
||
|
|
||
|
bool LaunchSettings::HandleCommandline(int argc, char* argv[])
|
||
|
{
|
||
|
std::vector<std::wstring> args;
|
||
|
args.reserve(argc);
|
||
|
for(int i = 0; i < argc; ++i)
|
||
|
{
|
||
|
args.emplace_back(boost::nowide::widen(argv[i]));
|
||
|
}
|
||
|
|
||
|
return HandleCommandline(args);
|
||
|
}
|
||
|
|
||
|
bool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)
|
||
|
{
|
||
|
namespace po = boost::program_options;
|
||
|
po::options_description desc{ "Launch options" };
|
||
|
desc.add_options()
|
||
|
("help,h", "This help screen")
|
||
|
("version,v", "Displays the version of Cemu")
|
||
|
|
||
|
("game,g", po::wvalue<std::wstring>(), "Path of game to launch")
|
||
|
("mlc,m", po::wvalue<std::wstring>(), "Custom mlc folder location")
|
||
|
|
||
|
("fullscreen,f", po::value<bool>()->implicit_value(true), "Launch games in fullscreen mode")
|
||
|
("ud,u", po::value<bool>()->implicit_value(true), "Render output upside-down")
|
||
|
|
||
|
("account,a", po::value<std::string>(), "Persistent id of account")
|
||
|
|
||
|
("force-interpreter", po::value<bool>()->implicit_value(true), "Force interpreter CPU emulation, disables recompiler")
|
||
|
|
||
|
("act-url", po::value<std::string>(), "URL prefix for account server")
|
||
|
("ecs-url", po::value<std::string>(), "URL for ECS service");
|
||
|
|
||
|
|
||
|
po::options_description hidden{ "Hidden options" };
|
||
|
hidden.add_options()
|
||
|
("nsight", po::value<bool>()->implicit_value(true), "NSight debugging options")
|
||
|
("legacy", po::value<bool>()->implicit_value(true), "Intel legacy graphic mode");
|
||
|
|
||
|
po::options_description extractor{ "Extractor tool" };
|
||
|
extractor.add_options()
|
||
|
("extract,e", po::wvalue<std::wstring>(), "Path to WUD or WUX file for extraction")
|
||
|
("path,p", po::value<std::string>(), "Path of file to extract (for example meta/meta.xml)")
|
||
|
("output,o", po::wvalue<std::wstring>(), "Output path for extracted file.");
|
||
|
|
||
|
po::options_description all;
|
||
|
all.add(desc).add(hidden).add(extractor);
|
||
|
|
||
|
po::options_description visible;
|
||
|
visible.add(desc).add(extractor);
|
||
|
|
||
|
try
|
||
|
{
|
||
|
po::wcommand_line_parser parser{ args };
|
||
|
parser.allow_unregistered().options(all).style(po::command_line_style::allow_long | po::command_line_style::allow_short | po::command_line_style::allow_dash_for_short | po::command_line_style::case_insensitive |
|
||
|
po::command_line_style::long_allow_next |
|
||
|
po::command_line_style::short_allow_next |
|
||
|
po::command_line_style::allow_long_disguise);
|
||
|
|
||
|
const auto parsed_options = parser.run();
|
||
|
|
||
|
po::variables_map vm;
|
||
|
po::store(parsed_options, vm);
|
||
|
notify(vm);
|
||
|
|
||
|
if (vm.count("help"))
|
||
|
{
|
||
|
requireConsole();
|
||
|
std::cout << visible << std::endl;
|
||
|
return false; // exit in main
|
||
|
}
|
||
|
if (vm.count("version"))
|
||
|
{
|
||
|
requireConsole();
|
||
|
std::string versionStr = fmt::format("{}.{}{}", EMULATOR_VERSION_LEAD, EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_SUFFIX);
|
||
|
std::cout << versionStr << std::endl;
|
||
|
return false; // exit in main
|
||
|
}
|
||
|
|
||
|
if (vm.count("game"))
|
||
|
{
|
||
|
std::wstring tmp = vm["game"].as<std::wstring>();
|
||
|
// workaround for boost command_line_parser not trimming token for short name parameters despite short_allow_adjacent
|
||
|
if (tmp.size() > 0 && tmp.front() == '=')
|
||
|
tmp.erase(tmp.begin()+0);
|
||
|
|
||
|
s_load_game_file = tmp;
|
||
|
}
|
||
|
|
||
|
if (vm.count("mlc"))
|
||
|
{
|
||
|
std::wstring tmp = vm["mlc"].as<std::wstring>();
|
||
|
// workaround for boost command_line_parser not trimming token for short name parameters despite short_allow_adjacent
|
||
|
if (tmp.size() > 0 && tmp.front() == '=')
|
||
|
tmp.erase(tmp.begin() + 0);
|
||
|
|
||
|
s_mlc_path = tmp;
|
||
|
}
|
||
|
|
||
|
if (vm.count("account"))
|
||
|
{
|
||
|
const auto id = ConvertString<uint32>(vm["account"].as<std::string>(), 16);
|
||
|
if (id >= Account::kMinPersistendId)
|
||
|
s_persistent_id = id;
|
||
|
}
|
||
|
|
||
|
if (vm.count("fullscreen"))
|
||
|
s_fullscreen = vm["fullscreen"].as<bool>();
|
||
|
if (vm.count("ud"))
|
||
|
s_render_upside_down = vm["ud"].as<bool>();
|
||
|
|
||
|
if (vm.count("nsight"))
|
||
|
s_nsight_mode = vm["nsight"].as<bool>();
|
||
|
if (vm.count("legacy"))
|
||
|
s_force_intel_legacy = vm["legacy"].as<bool>();
|
||
|
|
||
|
if(vm.count("force-interpreter"))
|
||
|
s_force_interpreter = vm["force-interpreter"].as<bool>();
|
||
|
|
||
|
std::wstring extract_path, log_path;
|
||
|
std::string output_path;
|
||
|
if (vm.count("extract"))
|
||
|
extract_path = vm["extract"].as<std::wstring>();
|
||
|
if (vm.count("path"))
|
||
|
output_path = vm["path"].as<std::string>();
|
||
|
if (vm.count("output"))
|
||
|
log_path = vm["output"].as<std::wstring>();
|
||
|
|
||
|
// urls
|
||
|
if (vm.count("act-url"))
|
||
|
{
|
||
|
serviceURL_ACT = vm["act-url"].as<std::string>();
|
||
|
if (serviceURL_ACT.size() > 0 && serviceURL_ACT.back() == '/')
|
||
|
serviceURL_ACT.pop_back();
|
||
|
}
|
||
|
if (vm.count("ecs-url"))
|
||
|
serviceURL_ECS = vm["ecs-url"].as<std::string>();
|
||
|
|
||
|
if(!extract_path.empty())
|
||
|
{
|
||
|
ExtractorTool(extract_path, output_path, log_path);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
catch (const std::exception& ex)
|
||
|
{
|
||
|
std::string errorMsg;
|
||
|
errorMsg.append("Error while trying to parse command line parameter:\n");
|
||
|
errorMsg.append(ex.what());
|
||
|
wxMessageBox(errorMsg, wxT("Parameter error"), wxICON_ERROR);
|
||
|
//cemuLog_log(LogType::Force, ex.what());
|
||
|
//std::cout << "Command line parameter error: " << ex.what() << std::endl;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
bool LaunchSettings::ExtractorTool(std::wstring_view wud_path, std::string_view output_path, std::wstring_view log_path)
|
||
|
{
|
||
|
// extracting requires path of file
|
||
|
if (output_path.empty())
|
||
|
{
|
||
|
requireConsole();
|
||
|
puts("Cannot extract files because no source path was specified (-p)\n");
|
||
|
return false;
|
||
|
}
|
||
|
// mount wud
|
||
|
AES128_init();
|
||
|
FSTVolume* srcVolume = FSTVolume::OpenFromDiscImage(fs::path(wud_path));
|
||
|
if (!srcVolume)
|
||
|
{
|
||
|
requireConsole();
|
||
|
puts(fmt::format("Unable to open \"%s\"\n", fs::path(wud_path).generic_string()).c_str());
|
||
|
return false;
|
||
|
}
|
||
|
bool fileFound = false;
|
||
|
std::vector<uint8> fileData = srcVolume->ExtractFile(output_path, &fileFound);
|
||
|
delete srcVolume;
|
||
|
if (!fileFound)
|
||
|
{
|
||
|
requireConsole();
|
||
|
puts(fmt::format("Unable to read file \"%s\"\n", output_path).c_str());
|
||
|
return false;
|
||
|
}
|
||
|
// output on console (if no output path was specified)
|
||
|
if (!log_path.empty())
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
fs::path filename(std::wstring{ log_path });
|
||
|
|
||
|
filename /= boost::nowide::widen(std::string(output_path));
|
||
|
|
||
|
fs::path p = filename;
|
||
|
p.remove_filename();
|
||
|
|
||
|
fs::create_directories(p);
|
||
|
std::ofstream file(filename, std::ios::out | std::ios::binary);
|
||
|
file.write((const char*)fileData.data(), fileData.size());
|
||
|
file.flush();
|
||
|
file.close();
|
||
|
}
|
||
|
catch (const std::exception& ex)
|
||
|
{
|
||
|
forceLog_printf("can't write file: %s", ex.what());
|
||
|
puts(fmt::format("can't write file: %s\n", ex.what()).c_str());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// output to console
|
||
|
requireConsole();
|
||
|
printf("%.*s", (int)fileData.size(), fileData.data());
|
||
|
fflush(stdout);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|