Cemu/src/config/LaunchSettings.cpp

306 lines
8.8 KiB
C++
Raw Normal View History

2022-08-22 22:21:23 +02:00
#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 "config/NetworkSettings.h"
2022-08-22 22:21:23 +02:00
#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")
("title-id,t", po::value<std::string>(), "Title ID of the title to be launched (overridden by --game)")
2022-08-22 22:21:23 +02:00
("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")
Add GDB stub for debugging (#657) * Implement GDB stub debugger Can be enabled by using the "--enable-gdbstub" option (and the debugger GUI, although that's untested) which'll pause any game you launch at start-up. Will start at port 1337 although it'll eventually be user-editable. The code is a bit weirdly sorted and also just needs a general cleanup, so expect that eventually too. And uses egyptian braces but formatting was easier to do at the end, so that's also something to do. It has been tested to work with IDA Pro, Clion and the standalone interface for now, but I plan on writing some instructions in the PR to follow for people who want to use this. Memory breakpoints aren't possible yet, only execution breakpoints. This code was aimed to be decoupled from the existing debugger to be able to be ported to the Wii U for an equal debugging experience. That's also why it uses the Cafe OS's thread sleep and resuming functions whenever possible instead of using recompiler/interpreter controls. * Add memory writing and floating point registers support * Reformat code a bit * Format code to adhere to Cemu's coding style * Rework GDB Stub settings in GUI * Small styling fixes * Rework execution breakpoints Should work better in some edge cases now. But this should also allow for adding access breakpoints since it's now more separated. * Implement access breakpoints * Fix some issues with breakpoints * Fix includes for Linux * Fix unnecessary include * Tweaks for Linux compatibility * Use std::thread instead of std::jthread to fix MacOS support * Enable GDB read/write breakpoints on x86 only * Fix compilation for GCC compilers at least The thread type varies on some platforms, so supporting this is hell... but let's get it to compile on MacOS first. * Disable them for MacOS due to lack of ptrace --------- Co-authored-by: Exzap <13877693+Exzap@users.noreply.github.com>
2023-02-19 15:41:49 +01:00
("enable-gdbstub", po::value<bool>()->implicit_value(true), "Enable GDB stub to debug executables inside Cemu using an external debugger")
2022-08-22 22:21:23 +02:00
("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;
#if EMULATOR_VERSION_MINOR == 0
versionStr = fmt::format("{}.{}{}", EMULATOR_VERSION_LEAD, EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_SUFFIX);
#else
versionStr = fmt::format("{}.{}-{}{}", EMULATOR_VERSION_LEAD, EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_SUFFIX);
#endif
2022-08-22 22:21:23 +02:00
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("title-id"))
{
auto title_param = vm["title-id"].as<std::string>();
try {
if (title_param.starts_with('=')){
title_param.erase(title_param.begin());
}
s_load_title_id = std::stoull(title_param, nullptr, 16);
}
catch (std::invalid_argument const& e)
{
std::cerr << "Expected title_param ID as an unsigned 64-bit hexadecimal string\n";
}
}
2022-08-22 22:21:23 +02:00
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>();
Add GDB stub for debugging (#657) * Implement GDB stub debugger Can be enabled by using the "--enable-gdbstub" option (and the debugger GUI, although that's untested) which'll pause any game you launch at start-up. Will start at port 1337 although it'll eventually be user-editable. The code is a bit weirdly sorted and also just needs a general cleanup, so expect that eventually too. And uses egyptian braces but formatting was easier to do at the end, so that's also something to do. It has been tested to work with IDA Pro, Clion and the standalone interface for now, but I plan on writing some instructions in the PR to follow for people who want to use this. Memory breakpoints aren't possible yet, only execution breakpoints. This code was aimed to be decoupled from the existing debugger to be able to be ported to the Wii U for an equal debugging experience. That's also why it uses the Cafe OS's thread sleep and resuming functions whenever possible instead of using recompiler/interpreter controls. * Add memory writing and floating point registers support * Reformat code a bit * Format code to adhere to Cemu's coding style * Rework GDB Stub settings in GUI * Small styling fixes * Rework execution breakpoints Should work better in some edge cases now. But this should also allow for adding access breakpoints since it's now more separated. * Implement access breakpoints * Fix some issues with breakpoints * Fix includes for Linux * Fix unnecessary include * Tweaks for Linux compatibility * Use std::thread instead of std::jthread to fix MacOS support * Enable GDB read/write breakpoints on x86 only * Fix compilation for GCC compilers at least The thread type varies on some platforms, so supporting this is hell... but let's get it to compile on MacOS first. * Disable them for MacOS due to lack of ptrace --------- Co-authored-by: Exzap <13877693+Exzap@users.noreply.github.com>
2023-02-19 15:41:49 +01:00
if (vm.count("enable-gdbstub"))
s_enable_gdbstub = vm["enable-gdbstub"].as<bool>();
2022-08-22 22:21:23 +02:00
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);
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)
{
cemuLog_log(LogType::Force, "can't write file: {}", ex.what());
2022-08-22 22:21:23 +02:00
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;
}
void LaunchSettings::ChangeNetworkServiceURL(int ID){
NetworkService Network = static_cast<NetworkService>(ID);
switch (Network)
{
case NetworkService::Pretendo:
serviceURL_ACT = PretendoURLs::ACTURL;
serviceURL_ECS = PretendoURLs::ECSURL;
break;
case NetworkService::Custom:
serviceURL_ACT = GetNetworkConfig().urls.ACT.GetValue();
serviceURL_ECS = GetNetworkConfig().urls.ECS.GetValue();
break;
2022-10-11 09:17:34 +02:00
case NetworkService::Nintendo:
default:
serviceURL_ACT = NintendoURLs::ACTURL;
serviceURL_ECS = NintendoURLs::ECSURL;
break;
}
2022-10-11 09:17:34 +02:00
}