107 lines
3.1 KiB
C++
107 lines
3.1 KiB
C++
#include <windows.h>
|
|
#include <spdlog/spdlog.h>
|
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
|
#include <stdexcept>
|
|
#include <stdio.h>
|
|
#include <r3/binders/stub.h>
|
|
|
|
#if RE_DBG_INJECTED
|
|
#include <r3/binders/dbg_mem.h>
|
|
extern "C" {
|
|
// This is the part of Rayman3.exe main CRT setup that runs before main, but
|
|
// doesn't call it
|
|
void gh_pre_main(void);
|
|
}
|
|
#else
|
|
#include <r3/binders/static_mem.h>
|
|
#endif
|
|
|
|
#include <CLI11.hpp>
|
|
#include <magic_enum/magic_enum.hpp>
|
|
|
|
extern "C" int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
LPSTR *cmdline, int showCmd);
|
|
|
|
int mainImpl(int argc, char **argv) {
|
|
std::shared_ptr<spdlog::logger> logger = spdlog::stderr_color_mt("game_re");
|
|
spdlog::set_default_logger(logger);
|
|
|
|
SPDLOG_INFO("Starting Reman 3: The hooded ones");
|
|
CLI::App app("Reman 3: The hooded ones");
|
|
std::string log_level = "info";
|
|
app.add_option("-l,--log-level", log_level, "Log level");
|
|
CLI11_PARSE(app, argc, argv);
|
|
|
|
auto log_level_enum =
|
|
magic_enum::enum_cast<spdlog::level::level_enum>(log_level);
|
|
if (log_level_enum.has_value()) {
|
|
spdlog::set_level(log_level_enum.value());
|
|
} else {
|
|
SPDLOG_ERROR("Invalid log level: {}", log_level);
|
|
return 1;
|
|
}
|
|
|
|
try {
|
|
#if RE_DBG_INJECTED
|
|
gh_init_dbg_loader();
|
|
gh_pre_main();
|
|
#else
|
|
gh_init_data_segment();
|
|
#endif
|
|
|
|
r3_main(GetModuleHandle(NULL), NULL, (char **)argv, SW_SHOW);
|
|
} catch (const std::exception &e) {
|
|
SPDLOG_ERROR("Unhandled exception: {}", e.what());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if RE_DBG_INJECTED
|
|
static void setupWindowsStdErrLogging() {
|
|
// Check if stderr is redirected
|
|
HANDLE stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
|
|
DWORD handleType = GetFileType(stderrHandle);
|
|
bool isRedirected = (handleType != FILE_TYPE_UNKNOWN);
|
|
if (!isRedirected && AttachConsole(ATTACH_PARENT_PROCESS)) {
|
|
freopen("CONOUT$", "wb", stderr);
|
|
HANDLE conOut = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
|
OPEN_EXISTING, 0, NULL);
|
|
DWORD mode{};
|
|
if (GetConsoleMode(conOut, &mode))
|
|
SetConsoleMode(conOut, mode | ENABLE_VIRTUAL_TERMINAL_INPUT);
|
|
SetStdHandle(STD_ERROR_HANDLE, conOut);
|
|
}
|
|
}
|
|
extern "C" int __declspec(dllexport) __cdecl re_dbg_attached(
|
|
const char *cmdLine_) {
|
|
|
|
auto split = CLI::detail::split_program_name(cmdLine_);
|
|
auto cmdLine = std::move(split.second);
|
|
cmdLine =
|
|
CLI::detail::find_and_modify(cmdLine, "=", CLI::detail::escape_detect);
|
|
|
|
auto args = CLI::detail::split_up(std::move(cmdLine));
|
|
// Remove arguments to Rayman3p launcher
|
|
args.erase(args.begin());
|
|
// Remove empty
|
|
args.erase(std::remove(args.begin(), args.end(), std::string{}), args.end());
|
|
|
|
std::vector<char *> args_c{split.first.data()};
|
|
for (auto &arg : args) {
|
|
args_c.push_back(arg.data());
|
|
}
|
|
args_c.push_back(nullptr);
|
|
|
|
// Attach process console
|
|
setupWindowsStdErrLogging();
|
|
try {
|
|
return mainImpl(args_c.size() - 1, args_c.data());
|
|
} catch (...) {
|
|
SPDLOG_ERROR("Unhandled exception in re_dbg_attached");
|
|
return 1;
|
|
}
|
|
}
|
|
#else
|
|
int main(int argc, char **argv) { return mainImpl(argc, argv); }
|
|
#endif |