reman3/game_re/r3/main.cxx

115 lines
3.3 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>
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<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