#include #include #include #include #include #include #if RE_DBG_INJECTED #include 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 #endif #include #include FnD3Create8 getDirect3DCreate8() { HMODULE hModule = LoadLibrary("d3d8.dll"); if (hModule != NULL) { return (FnD3Create8)GetProcAddress(hModule, "Direct3DCreate8"); } return nullptr; } extern "C" int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline, int showCmd); int mainImpl(int argc, char **argv) { std::shared_ptr 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(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 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