Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: Add argument to pass an argument to the game #2135

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/core/linker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Linker::Linker() : memory{Memory::Instance()} {}

Linker::~Linker() = default;

void Linker::Execute() {
void Linker::Execute(const std::vector<std::string> args) {
if (Config::debugDump()) {
DebugDump();
}
Expand Down Expand Up @@ -101,14 +101,20 @@ void Linker::Execute() {

memory->SetupMemoryRegions(fmem_size, use_extended_mem1, use_extended_mem2);

main_thread.Run([this, module](std::stop_token) {
main_thread.Run([this, module, args](std::stop_token) {
Common::SetCurrentThreadName("GAME_MainThread");
LoadSharedLibraries();

// Start main module.
EntryParams params{};
params.argc = 1;
params.argv[0] = "eboot.bin";
if (!args.empty()) {
params.argc = args.size() + 1;
for (int i = 0; i < args.size() && i < 32; i++) {
params.argv[i + 1] = args[i].c_str();
}
}
params.entry_addr = module->GetEntryAddress();
RunMainEntry(&params);
});
Expand Down
4 changes: 2 additions & 2 deletions src/core/linker.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class Linker;
struct EntryParams {
int argc;
u32 padding;
const char* argv[3];
const char* argv[33];
VAddr entry_addr;
};

Expand Down Expand Up @@ -143,7 +143,7 @@ class Linker {
void Relocate(Module* module);
bool Resolve(const std::string& name, Loader::SymbolType type, Module* module,
Loader::SymbolRecord* return_info);
void Execute();
void Execute(const std::vector<std::string> args = std::vector<std::string>());
void DebugDump();

private:
Expand Down
13 changes: 11 additions & 2 deletions src/emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Emulator::~Emulator() {
Config::saveMainWindow(config_dir / "config.toml");
}

void Emulator::Run(const std::filesystem::path& file) {
void Emulator::Run(const std::filesystem::path& file, const std::vector<std::string> args) {
// Applications expect to be run from /app0 so mount the file's parent path as app0.
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto game_folder = file.parent_path();
Expand Down Expand Up @@ -151,6 +151,15 @@ void Emulator::Run(const std::filesystem::path& file) {
if (const auto raw_attributes = param_sfo->GetInteger("ATTRIBUTE")) {
psf_attributes.raw = *raw_attributes;
}
if (!args.empty()) {
int argc = args.size() > 32 ? 32 : args.size();
for (int i = 0; i < argc; i++) {
LOG_INFO(Loader, "Game argument {}: {}", i, args[i]);
}
if (args.size() > 32) {
LOG_ERROR(Loader, "Too many game arguments, only passing the first 32");
}
}
}

const auto pic1_path = mnt->GetHostPath("/app0/sce_sys/pic1.png");
Expand Down Expand Up @@ -238,7 +247,7 @@ void Emulator::Run(const std::filesystem::path& file) {
}
#endif

linker->Execute();
linker->Execute(args);

window->InitTimers();
while (window->IsOpen()) {
Expand Down
3 changes: 2 additions & 1 deletion src/emulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class Emulator {
Emulator();
~Emulator();

void Run(const std::filesystem::path& file);
void Run(const std::filesystem::path& file,
const std::vector<std::string> args = std::vector<std::string>());
void UpdatePlayTime(const std::string& serial);

private:
Expand Down
28 changes: 27 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ int main(int argc, char* argv[]) {

bool has_game_argument = false;
std::string game_path;
std::vector<std::string> game_args{};

// Map of argument strings to lambda functions
std::unordered_map<std::string, std::function<void(int&)>> arg_map = {
Expand All @@ -37,6 +38,9 @@ int main(int argc, char* argv[]) {
std::cout << "Usage: shadps4 [options] <elf or eboot.bin path>\n"
"Options:\n"
" -g, --game <path|ID> Specify game path to launch\n"
" -- ... Parameters passed to the game ELF. "
"Needs to be at the end of the line, and everything after \"--\" is a "
"game argument.\n"
" -p, --patch <patch_file> Apply specified patch file\n"
" -f, --fullscreen <true|false> Specify window initial fullscreen "
"state. Does not overwrite the config file.\n"
Expand Down Expand Up @@ -126,6 +130,28 @@ int main(int argc, char* argv[]) {
// Assume the last argument is the game file if not specified via -g/--game
game_path = argv[i];
has_game_argument = true;
} else if (std::string(argv[i]) == "--") {
if (i + 1 == argc) {
std::cerr << "Warning: -- is set, but no game arguments are added!\n";
break;
}
for (int j = i + 1; j < argc; j++) {
game_args.push_back(argv[j]);
}
break;
} else if (std::string(argv[i + 1]) == "--") {
if (!has_game_argument) {
game_path = argv[i];
has_game_argument = true;
}
if (i + 2 == argc) {
std::cerr << "Warning: -- is set, but no game arguments are added!\n";
break;
}
for (int j = i + 2; j < argc; j++) {
game_args.push_back(argv[j]);
}
break;
} else {
std::cerr << "Unknown argument: " << cur_arg << ", see --help for info.\n";
return 1;
Expand Down Expand Up @@ -166,7 +192,7 @@ int main(int argc, char* argv[]) {

// Run the emulator with the resolved eboot path
Core::Emulator emulator;
emulator.Run(eboot_path);
emulator.Run(eboot_path, game_args);

return 0;
}
28 changes: 27 additions & 1 deletion src/qt_gui/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ int main(int argc, char* argv[]) {
bool has_command_line_argument = argc > 1;
bool show_gui = false, has_game_argument = false;
std::string game_path;
std::vector<std::string> game_args{};

// Map of argument strings to lambda functions
std::unordered_map<std::string, std::function<void(int&)>> arg_map = {
Expand All @@ -43,6 +44,9 @@ int main(int argc, char* argv[]) {
" No arguments: Opens the GUI.\n"
" -g, --game <path|ID> Specify <eboot.bin or elf path> or "
"<game ID (CUSAXXXXX)> to launch\n"
" -- ... Parameters passed to the game ELF. "
"Needs to be at the end of the line, and everything after \"--\" is a "
"game argument.\n"
" -p, --patch <patch_file> Apply specified patch file\n"
" -s, --show-gui Show the GUI\n"
" -f, --fullscreen <true|false> Specify window initial fullscreen "
Expand Down Expand Up @@ -131,6 +135,28 @@ int main(int argc, char* argv[]) {
// Assume the last argument is the game file if not specified via -g/--game
game_path = argv[i];
has_game_argument = true;
} else if (std::string(argv[i]) == "--") {
if (i + 1 == argc) {
std::cerr << "Warning: -- is set, but no game arguments are added!\n";
break;
}
for (int j = i + 1; j < argc; j++) {
game_args.push_back(argv[j]);
}
break;
} else if (std::string(argv[i + 1]) == "--") {
if (!has_game_argument) {
game_path = argv[i];
has_game_argument = true;
}
if (i + 2 == argc) {
std::cerr << "Warning: -- is set, but no game arguments are added!\n";
break;
}
for (int j = i + 2; j < argc; j++) {
game_args.push_back(argv[j]);
}
break;
} else {
std::cerr << "Unknown argument: " << cur_arg << ", see --help for info.\n";
return 1;
Expand Down Expand Up @@ -181,7 +207,7 @@ int main(int argc, char* argv[]) {

// Run the emulator with the resolved game path
Core::Emulator emulator;
emulator.Run(game_file_path.string());
emulator.Run(game_file_path.string(), game_args);
if (!show_gui) {
return 0; // Exit after running the emulator without showing the GUI
}
Expand Down