mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
37218e7fe0
As noted in #567, a filesystem path that contains non-ascii will break a lot if using a clang toolchain. Luckily, fmtlib has a lossy utf8 convert when you use it to print a path (after including `fmt/std.h`). The vast majority of this diff is just removing `.string()` from paths inside loggings calls. There are some callsites I _didn't_ touch, mainly the options, because it would be an ABI break to change those to be wide strings and I cbf looking into settings upgrades. There are also some spots (avs mountpath remapping, for example) where the path is guaranteed to be ascii, so I didn't modify them. ImGui doesn't appear to easily support wide strings (I mean, surely it does, but I'm not gonna look too far into it) so I mostly just left those alone too, with a few spots modified to re-use fmtlib's lossy utf8. Some of the changes are basically never gonna be hit IRL, like who would put a file with a non-ascii _extension_ along with their modules? But the diff is (I hope) pretty easy to validate as OK. Testing has been somewhat minimal, I fired up the GCC build of spice2x in a dodgy folder name, got mojibake (running via wine in linux so take that as you will), ran the unmodified clang spice and crashed the same way the reporter did. After modification, I get the exact same mojibake so I assume if the terminal enjoys utf8 it'll display OK. Claude (only used for review) thinks the commit is fine but is annoyed that I use `fmt::detail` in the appdata censoring, which is part of the private API; personally I don't care because it's pretty stable.
153 lines
5.7 KiB
C++
153 lines
5.7 KiB
C++
#include "game.h"
|
|
|
|
#include "launcher/launcher.h"
|
|
#include "util/fileutils.h"
|
|
#include "util/libutils.h"
|
|
#include "util/logging.h"
|
|
|
|
namespace avs {
|
|
|
|
namespace game {
|
|
|
|
// function names
|
|
const char ENTRY_INIT_NAME[] = "dll_entry_init";
|
|
const char ENTRY_MAIN_NAME[] = "dll_entry_main";
|
|
|
|
// functions
|
|
typedef bool (*ENTRY_INIT_T)(char *, void *);
|
|
typedef void (*ENTRY_MAIN_T)(void);
|
|
ENTRY_INIT_T dll_entry_init;
|
|
ENTRY_MAIN_T dll_entry_main;
|
|
|
|
// properties
|
|
char MODEL[4] = {'0', '0', '0', '\x00'};
|
|
char DEST[2] = {'0', '\x00'};
|
|
char SPEC[2] = {'0', '\x00'};
|
|
char REV[2] = {'0', '\x00'};
|
|
char EXT[11] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '\x00'};
|
|
|
|
// handle
|
|
HINSTANCE DLL_INSTANCE;
|
|
std::string DLL_NAME;
|
|
|
|
bool is_model(const char *model) {
|
|
return _stricmp(MODEL, model) == 0;
|
|
}
|
|
|
|
bool is_model(const char *model, const char *ext) {
|
|
return is_model(model) && is_ext(ext);
|
|
}
|
|
|
|
bool is_model(const std::initializer_list<const char *> model_list) {
|
|
for (auto &model : model_list) {
|
|
if (is_model(model)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool is_ext(const char *ext) {
|
|
return _stricmp(EXT, ext) == 0;
|
|
}
|
|
|
|
bool is_ext(int datecode_min, int datecode_max) {
|
|
|
|
// range check
|
|
long datecode = strtol(EXT, NULL, 10);
|
|
return datecode_min <= datecode && datecode <= datecode_max;
|
|
}
|
|
|
|
std::string get_identifier() {
|
|
return fmt::format("{}:{}:{}:{}:{}",
|
|
avs::game::MODEL,
|
|
avs::game::DEST,
|
|
avs::game::SPEC,
|
|
avs::game::REV,
|
|
avs::game::EXT);
|
|
}
|
|
|
|
void load_dll() {
|
|
log_info("avs-game", "loading DLL '{}'", DLL_NAME);
|
|
|
|
// load game instance
|
|
const auto dll_path = MODULE_PATH / DLL_NAME;
|
|
log_info("avs-game", "DLL path: {}", dll_path);
|
|
|
|
// MAX_PATH is 260
|
|
if (const auto dll_path_len = dll_path.wstring().length(); 130 <= dll_path_len) {
|
|
log_warning(
|
|
"avs-game",
|
|
"PATH TOO LONG WARNING\n\n"
|
|
"-------------------------------------------------------------------\n"
|
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
|
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
|
" PATH TOO LONG \n"
|
|
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
|
"The path '{}'\n"
|
|
" has a length of {}\n"
|
|
"Most of these games may behave unexpectedly when the path is too\n"
|
|
"long, often resulting in random crashes. Move the game contents to\n"
|
|
"a directory with shorter path.\n"
|
|
"-------------------------------------------------------------------\n\n",
|
|
dll_path, dll_path_len);
|
|
}
|
|
|
|
// ddr gamemdx.dll user error
|
|
if (avs::game::is_model("MDX") && DLL_NAME == "gamemdx.dll") {
|
|
log_warning(
|
|
"ddr",
|
|
"BAD GAME DLL ERROR\n\n"
|
|
"!!! !!!\n"
|
|
"!!! -exec gamemdx.dll was specified !!!\n"
|
|
"!!! this is the wrong DLL; the game will not load !!!\n"
|
|
"!!! remove -exec argument and try again. !!!\n"
|
|
"!!! !!!\n"
|
|
);
|
|
log_fatal("ddr", "BAD GAME DLL ERROR (don't use -exec gamemdx.dll, that's the wrong DLL)");
|
|
}
|
|
|
|
// file not found on disk
|
|
if (!fileutils::file_exists(dll_path)) {
|
|
log_warning("avs-game", "game DLL could not be found on disk: {}", dll_path);
|
|
log_warning("avs-game", "double check -exec and -modules parameters; unless you know what you're doing, leave them blank");
|
|
}
|
|
|
|
if (fileutils::verify_header_pe(dll_path)) {
|
|
DLL_INSTANCE = libutils::load_library(dll_path);
|
|
}
|
|
|
|
// load entry points
|
|
dll_entry_init = (ENTRY_INIT_T) libutils::get_proc(DLL_INSTANCE, ENTRY_INIT_NAME);
|
|
dll_entry_main = (ENTRY_MAIN_T) libutils::get_proc(DLL_INSTANCE, ENTRY_MAIN_NAME);
|
|
log_info("avs-game", "loaded {} successfully ({})", DLL_NAME, fmt::ptr(DLL_INSTANCE));
|
|
}
|
|
|
|
bool entry_init(char *sid_code, void *app_param) {
|
|
auto current_entry_init = (ENTRY_INIT_T) libutils::get_proc(DLL_INSTANCE, ENTRY_INIT_NAME);
|
|
|
|
if (dll_entry_init != current_entry_init) {
|
|
log_info("avs-game", "dll_entry_init is hooked");
|
|
|
|
dll_entry_init = current_entry_init;
|
|
}
|
|
|
|
return dll_entry_init(sid_code, app_param);
|
|
}
|
|
|
|
void entry_main() {
|
|
auto current_entry_main = (ENTRY_MAIN_T) libutils::get_proc(DLL_INSTANCE, ENTRY_MAIN_NAME);
|
|
|
|
if (dll_entry_main != current_entry_main) {
|
|
log_info("avs-game", "dll_entry_main is hooked");
|
|
|
|
dll_entry_main = current_entry_main;
|
|
}
|
|
|
|
dll_entry_main();
|
|
}
|
|
}
|
|
}
|