diff --git a/include/game_api.h b/include/game_api.h index a9ab35e..17d0e20 100644 --- a/include/game_api.h +++ b/include/game_api.h @@ -19,109 +19,104 @@ Created By: #include "qmmapi.h" #include "qvm.h" -struct supportedgame; -struct supportedgame_funcs { - // this section is made by GEN_INFO(GAME) +// engine/mod API type +enum APIType { + QMM_API_ERROR, + + QMM_API_QVM, + + QMM_API_DLLENTRY, + QMM_API_GETGAMEAPI, + QMM_API_GETMODULEAPI, +}; +const char* APIType_Name(APIType); +const char* APIType_Function(APIType); + +struct api_supportedgame; +// this struct is defined by GEN_GAME_FUNCS_QVM(GAME) or GEN_GAME_FUNCS(GAME) +struct api_supportedgame_funcs { int* qmm_eng_msgs; // array of engine messages used by QMM int* qmm_mod_msgs; // array of mod messages used by QMM - const char* (*pfnEngMsgNames)(intptr_t); // pointer to a function that returns a string for a given engine message + const char* (*pfnEngMsgNames)(intptr_t); // pointer to a function that returns a string for a given api message const char* (*pfnModMsgNames)(intptr_t); // pointer to a function that returns a string for a given mod message - // this section is made by GEN_DLLQVM(GAME), GEN_DLL(GAME), or GEN_GGA(GAME) - bool(*pfnAutoDetect)(bool, supportedgame*); // pointer to a function that handles auto-detection logic for a game (NULL = no auto-detection) - qvm_syscall pfnqvmsyscall; // pointer to a function that handles mod->engine calls from a QVM (NULL = not supported) - mod_dllEntry pfndllEntry; // pointer to a function that handles dllEntry entry for a game (NULL = not supported) - mod_GetGameAPI pfnGetGameAPI; // pointer to a function that handles GetGameAPI entry for a game (NULL = not supported) - bool(*pfnModLoad)(void*, bool); // pointer to a function that handles mod loading logic after a DLL is loaded + bool(*pfnAutoDetect)(api_supportedgame*, APIType); // pointer to a function that handles auto-detection logic for a game. return true to say "that's me!" + void*(*pfnEntry)(void*, void*, APIType); // pointer to a function that handles entry point logic for a game + bool(*pfnModLoad)(void*, APIType); // pointer to a function that handles mod loading logic after a DLL is loaded with LoadLibrary/dlopen void(*pfnModUnload)(); // pointer to a function that handles mod unloading logic before a DLL is unloaded + + qvm_syscall pfnQVMSyscall; // pointer to a function that handles mod->engine calls from a QVM (NULL = not supported) }; + // some information for each game engine supported by QMM -struct supportedgame { +struct api_supportedgame { const char* dllname; // default dll mod filename const char* qvmname; // default qvm mod filename (NULL = not supported) const char* moddir; // default moddir name const char* gamename_long; // long, descriptive, game name - // this section is made by GEN_FUNCS(GAME) + // this section is made by GEN_GAME_INFO(GAME) const char* gamename_short; // short initials for game - supportedgame_funcs* funcs; // function pointers for this game + api_supportedgame_funcs* funcs; // function pointers for this game int max_syscall_args; // max number of syscall args that this game needs (unused for now, but nice to have easily available) int max_vmmain_args; // max number of vmmain args that this game needs (unused for now, but nice to have easily available) }; -extern std::vector g_supportedgames; +extern std::vector api_supportedgames; // macros to make game support a bit easier to do -// used at the top of game_api.cpp and game_XYZ.cpp -// ====== -// generate extern for each game's functions -#define GEN_EXTS(game) extern supportedgame_funcs game##_funcs; - -// used in supportedgames entry in game_api.cpp -// ====== -// generate extern for each game's shortcode and supportedgame_funcs struct (used in game_api.cpp) -#define GEN_INFO(game) #game , &game##_funcs - -// used in game_XYZ.cpp -// ====== -// generate struct info for the game-specific functions and arrays - -// dllEntry/vmMain game with QVM support -#define GEN_DLLQVM(game) \ -static const char* game##_eng_msg_names(intptr_t); \ -static const char* game##_mod_msg_names(intptr_t); \ -static bool game##_autodetect(bool, supportedgame*); \ -static intptr_t game##_syscall(intptr_t cmd, ...); \ -static intptr_t game##_vmMain(intptr_t cmd, ...); \ -static int game##_qvmsyscall(uint8_t*, int, int*); \ -static void game##_dllEntry(eng_syscall); \ -static bool game##_mod_load(void*, bool); \ -static void game##_mod_unload(); \ -supportedgame_funcs game##_funcs = { \ - game##_qmm_eng_msgs, game##_qmm_mod_msgs, game##_eng_msg_names, game##_mod_msg_names, \ - game##_autodetect, game##_qvmsyscall, game##_dllEntry, nullptr, \ - game##_mod_load, game##_mod_unload \ -} +// generate extern for each game's functions (used at the top of game_api.cpp and game_XYZ.cpp) +#define GEN_GAME_EXTS(game) extern api_supportedgame_funcs game##_funcs; + +// generate extern for each game's shortcode and funcs struct (used in supportedgames entry in game_api.cpp) +#define GEN_GAME_INFO(game) #game , &game##_funcs + +// generate struct info for the game-specific functions and arrays (used in game_XYZ.cpp) -// dllEntry/vmMain game with no QVM support -#define GEN_DLL(game) \ -static const char* game##_eng_msg_names(intptr_t); \ -static const char* game##_mod_msg_names(intptr_t); \ -static bool game##_autodetect(bool, supportedgame*); \ +// game with QVM support +#define GEN_GAME_FUNCS_QVM(game) \ +static const char* game##_EngMsgNames(intptr_t); \ +static const char* game##_ModMsgNames(intptr_t); \ +static bool game##_AutoDetect(api_supportedgame*, APIType); \ +static void* game##_Entry(void*, void*, APIType); \ +static bool game##_ModLoad(void*, APIType); \ +static void game##_ModUnload(); \ static intptr_t game##_syscall(intptr_t cmd, ...); \ static intptr_t game##_vmMain(intptr_t cmd, ...); \ -static void game##_dllEntry(eng_syscall); \ -static bool game##_mod_load(void*, bool); \ -static void game##_mod_unload(); \ -supportedgame_funcs game##_funcs = { \ - game##_qmm_eng_msgs, game##_qmm_mod_msgs, game##_eng_msg_names, game##_mod_msg_names, \ - game##_autodetect, nullptr, game##_dllEntry, nullptr, \ - game##_mod_load, game##_mod_unload \ +static int game##_QVMSyscall(uint8_t*, int, int*); \ +api_supportedgame_funcs game##_funcs = { \ + game##_qmm_eng_msgs, game##_qmm_mod_msgs, \ + game##_EngMsgNames, game##_ModMsgNames, \ + game##_AutoDetect, game##_Entry, \ + game##_ModLoad, game##_ModUnload, \ + game##_QVMSyscall, \ } -// GetGameAPI game -#define GEN_GGA(game) \ -static const char* game##_eng_msg_names(intptr_t); \ -static const char* game##_mod_msg_names(intptr_t); \ -static bool game##_autodetect(bool, supportedgame*); \ +// game with no QVM support +#define GEN_GAME_FUNCS(game) \ +static const char* game##_EngMsgNames(intptr_t); \ +static const char* game##_ModMsgNames(intptr_t); \ +static bool game##_AutoDetect(api_supportedgame*, APIType); \ +static void* game##_Entry(void*, void*, APIType); \ +static bool game##_ModLoad(void*, APIType); \ +static void game##_ModUnload(); \ static intptr_t game##_syscall(intptr_t cmd, ...); \ static intptr_t game##_vmMain(intptr_t cmd, ...); \ -static void* game##_GetGameAPI(void*, void*); \ -static bool game##_mod_load(void*, bool); \ -static void game##_mod_unload(); \ -supportedgame_funcs game##_funcs = { \ - game##_qmm_eng_msgs, game##_qmm_mod_msgs, game##_eng_msg_names, game##_mod_msg_names, \ - game##_autodetect, nullptr, nullptr, game##_GetGameAPI, \ - game##_mod_load, game##_mod_unload \ +api_supportedgame_funcs game##_funcs = { \ + game##_qmm_eng_msgs, game##_qmm_mod_msgs, \ + game##_EngMsgNames, game##_ModMsgNames, \ + game##_AutoDetect, game##_Entry, \ + game##_ModLoad, game##_ModUnload, \ + nullptr, \ } -// generate a case/string line for use in the _msg_names functions +// generate a case/string line for use in the *MsgNames functions #define GEN_CASE(x) case x: return #x -// a list of all the engine messages/constants used by QMM. if you change this, update the GEN_QMM_MSGS macro +// a list of all the engine messages/constants used by QMM. if you change this, update the GEN_GAME_QMM_MSGS macro enum { // general purpose QMM_G_PRINT, QMM_G_ERROR, QMM_G_ARGV, QMM_G_ARGC, QMM_G_SEND_CONSOLE_COMMAND, QMM_G_GET_CONFIGSTRING, @@ -131,11 +126,11 @@ enum { QMM_G_FS_FOPEN_FILE, QMM_G_FS_READ, QMM_G_FS_WRITE, QMM_G_FS_FCLOSE_FILE, QMM_EXEC_APPEND, QMM_FS_READ, }; -// a list of all the mod messages used by QMM. if you change this, update the GEN_QMM_MSGS macro +// a list of all the mod messages used by QMM. if you change this, update the GEN_GAME_QMM_MSGS macro enum { QMM_GAME_INIT, QMM_GAME_SHUTDOWN, QMM_GAME_CONSOLE_COMMAND, }; // macro to easily output game-specific message values to match the enums above. this macro goes in game_*.cpp -#define GEN_QMM_MSGS(game) \ +#define GEN_GAME_QMM_MSGS(game) \ static int game##_qmm_eng_msgs[] = { \ G_PRINT, G_ERROR, G_ARGV, G_ARGC, G_SEND_CONSOLE_COMMAND, G_GET_CONFIGSTRING, \ G_CVAR_REGISTER, G_CVAR_VARIABLE_STRING_BUFFER, G_CVAR_VARIABLE_INTEGER_VALUE, CVAR_SERVERINFO, CVAR_ROM, \ @@ -235,7 +230,7 @@ constexpr int QMM_MAX_SYSCALL_ARGS = 17; // ----- QVM stuff ----- // --------------------- -// these macros handle qvm syscall arguments in GAME_qvmsyscall functions in game_*.cpp +// these macros handle qvm syscall arguments in GAME_QVMSyscall functions in game_*.cpp // this gets an argument value (evaluate to an intptr_t) #define VMARG(arg) (intptr_t)args[arg] diff --git a/include/main.h b/include/main.h index 30b4d7a..cbab503 100644 --- a/include/main.h +++ b/include/main.h @@ -29,10 +29,11 @@ struct gameinfo { std::string cfg_path; // qmm config file path eng_syscall pfnsyscall = nullptr; // game-specific wrapper for syscall. given to plugins and called by QMM mod_vmMain pfnvmMain = nullptr; // game-specific wrapper for vmMain. given to plugins and called by QMM - supportedgame* game = nullptr; // loaded engine from supported games table from game_api.cpp + api_supportedgame* game = nullptr; // loaded engine from supported games table from game_api.cpp void* qmm_module_ptr = nullptr; // qmm module pointer bool is_auto_detected = false; // was this engine auto-detected? bool is_shutdown = false; // is game shutting down due to G_ERROR? avoids calling G_ERROR again from GAME_SHUTDOWN + APIType api = QMM_API_ERROR; // engine api that QMM was loaded with }; extern gameinfo g_gameinfo; diff --git a/include/mod.h b/include/mod.h index 1919c31..6ec7347 100644 --- a/include/mod.h +++ b/include/mod.h @@ -16,17 +16,18 @@ Created By: #include "qmmapi.h" #include "qvm.h" -struct mod { - void* dll = nullptr; - qvm vm = {}; - intptr_t vmbase = 0; - std::string path; +struct qmm_mod { + std::string path; // mod file path + qvm vm = {}; // QVM object + void* dll = nullptr; // OS DLL handle + intptr_t vmbase = 0; // base data segment address for QVMs (0 if DLL mod) + APIType api = QMM_API_ERROR; // engine api the mod DLL was loaded with }; -extern mod g_mod; +extern qmm_mod g_mod; -bool mod_load(mod& mod, std::string file); -void mod_unload(mod& mod); +bool mod_load(qmm_mod& mod, std::string file); +void mod_unload(qmm_mod& mod); #endif // QMM2_MOD_H diff --git a/include/osdef.h b/include/osdef.h index d6dd2c4..f78c487 100644 --- a/include/osdef.h +++ b/include/osdef.h @@ -36,14 +36,13 @@ Created By: #define EXT_DLL "dll" #define EXT_QVM "qvm" - #define PATH_MAX 4096 - #define strcasecmp _stricmp + #define PATH_MAX MAX_PATH #define dlopen(file, x) ((void*)LoadLibrary(file)) - #define dlsym(dll, func) ((void*)GetProcAddress((HMODULE)(dll), (func))) - #define dlclose(dll) FreeLibrary((HMODULE)(dll)) - #define mkdir(path, x) _mkdir(path) - #define osdef_get_milliseconds GetTickCount64 - const char* dlerror(); // this will return the last error from any win32 function, not just library functions + #define dlsym(dll, func) ((void*)GetProcAddress((HMODULE)(dll), (func))) + #define dlclose(dll) FreeLibrary((HMODULE)(dll)) + #define mkdir(path, x) _mkdir(path) + #define osdef_get_milliseconds GetTickCount64 + const char* dlerror(); // this will return the last error from any win32 function, not just library functions #elif defined(QMM_OS_LINUX) @@ -67,7 +66,6 @@ Created By: #define EXT_DLL "so" #define EXT_QVM "qvm" uint64_t osdef_get_milliseconds(); - void MessageBoxA(void* handle, const char* message, const char* title, int flags); #else // !QMM_OS_WINDOWS && !QMM_OS_LINUX diff --git a/include/plugin.h b/include/plugin.h index 23079b1..36bbe55 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -30,7 +30,7 @@ using plugin_pluginmessage = void (*)(plugin_id from_plid, const char* message, // QMM_QVMHandler using plugin_qvmhandler = int (*)(int cmd, int* args); -struct plugin { +struct qmm_plugin { void* dll = nullptr; std::string path; plugin_query QMM_Query = nullptr; @@ -54,18 +54,18 @@ struct plugin_globals { extern plugin_globals g_plugin_globals; -extern std::vector g_plugins; +extern std::vector g_plugins; // this ID is like the various syscall values. they go through the following function y=-x-1 when used as QVM function pointers // once the handler function is called, this is already undone with another y=-x-1 to get a positive number again #define QMM_QVM_FUNC_STARTING_ID 10000 -extern std::map g_registered_qvm_funcs; +extern std::map g_registered_qvm_funcs; const char* plugin_result_to_str(plugin_res res); // returns: -1 if failed to load and don't continue, 0 if failed to load and continue, 1 if loaded -int plugin_load(plugin& p, std::string file); +int plugin_load(qmm_plugin& p, std::string file); -void plugin_unload(plugin& p); +void plugin_unload(qmm_plugin& p); #endif // QMM2_PLUGIN_H diff --git a/src/game_api.cpp b/src/game_api.cpp index 548dd9a..548015b 100644 --- a/src/game_api.cpp +++ b/src/game_api.cpp @@ -18,29 +18,29 @@ Created By: intptr_t msg_G_PRINT, msg_GAME_INIT, msg_GAME_CONSOLE_COMMAND, msg_GAME_SHUTDOWN; // externs for each game's functions/structs -GEN_EXTS(COD11MP); -GEN_EXTS(CODMP); -GEN_EXTS(CODUOMP); -GEN_EXTS(JAMP); -GEN_EXTS(JK2MP); -GEN_EXTS(Q3A); -GEN_EXTS(RTCWMP); -GEN_EXTS(RTCWSP); -GEN_EXTS(SOF2MP); -GEN_EXTS(STVOYHM); -GEN_EXTS(WET); - -GEN_EXTS(JASP); -GEN_EXTS(JK2SP); -GEN_EXTS(MOHAA); -GEN_EXTS(MOHSH); -GEN_EXTS(MOHBT); -GEN_EXTS(Q2R); -GEN_EXTS(QUAKE2); -GEN_EXTS(SIN); -GEN_EXTS(SOF2SP); -GEN_EXTS(STEF2); -GEN_EXTS(STVOYSP); +GEN_GAME_EXTS(COD11MP); +GEN_GAME_EXTS(CODMP); +GEN_GAME_EXTS(CODUOMP); +GEN_GAME_EXTS(JAMP); +GEN_GAME_EXTS(JK2MP); +GEN_GAME_EXTS(Q3A); +GEN_GAME_EXTS(RTCWMP); +GEN_GAME_EXTS(RTCWSP); +GEN_GAME_EXTS(SOF2MP); +GEN_GAME_EXTS(STVOYHM); +GEN_GAME_EXTS(WET); + +GEN_GAME_EXTS(JASP); +GEN_GAME_EXTS(JK2SP); +GEN_GAME_EXTS(MOHAA); +GEN_GAME_EXTS(MOHSH); +GEN_GAME_EXTS(MOHBT); +GEN_GAME_EXTS(Q2R); +GEN_GAME_EXTS(QUAKE2); +GEN_GAME_EXTS(SIN); +GEN_GAME_EXTS(SOF2SP); +GEN_GAME_EXTS(STEF2); +GEN_GAME_EXTS(STVOYSP); // SP_DLL + MP_DLL - COD, RTCWMP & WET filename changes between linux/windows // UO_DLL - CODUO filename changes between linux/windows @@ -67,44 +67,78 @@ GEN_EXTS(STVOYSP); #define X64_DLL X64_SUF_DLL "." EXT_DLL // add your game's info data here -std::vector g_supportedgames = { +std::vector api_supportedgames = { // mod filename qvm mod filename default moddir full gamename short name/funcs #syscall#vmmain // vmMain games - { "qagame" MOD_DLL, "vm/qagame.qvm", "baseq3", "Quake 3 Arena", GEN_INFO(Q3A), 13, 4 }, - { "qagame" SP_DLL X64_DLL, nullptr, ".", "Return to Castle Wolfenstein (SP)", GEN_INFO(RTCWSP), 13, 5 }, - { "jk2mpgame" MOD_DLL, "vm/jk2mpgame.qvm", "base", "Jedi Knight 2: Jedi Outcast (MP)", GEN_INFO(JK2MP), 13, 3 }, - { "jampgame" MOD_DLL, nullptr, "base", "Jedi Knight: Jedi Academy (MP)", GEN_INFO(JAMP), 13, 6 }, - { "qagame" MP_DLL X64_DLL, nullptr, "etmain", "Wolfenstein: Enemy Territory", GEN_INFO(WET), 13, 5 }, - { "qagame" MP_DLL X64_DLL, "vm/qagame.mp.qvm", "main", "Return to Castle Wolfenstein (MP)", GEN_INFO(RTCWMP), 13, 5 }, + { "qagame" MOD_DLL, "vm/qagame.qvm", "baseq3", "Quake 3 Arena", GEN_GAME_INFO(Q3A), 13, 4 }, + { "qagame" SP_DLL X64_DLL, nullptr, ".", "Return to Castle Wolfenstein (SP)", GEN_GAME_INFO(RTCWSP), 13, 5 }, + { "jk2mpgame" MOD_DLL, "vm/jk2mpgame.qvm", "base", "Jedi Knight 2: Jedi Outcast (MP)", GEN_GAME_INFO(JK2MP), 13, 3 }, + { "jampgame" MOD_DLL, nullptr, "base", "Jedi Knight: Jedi Academy (MP)", GEN_GAME_INFO(JAMP), 13, 6 }, + { "qagame" MP_DLL X64_DLL, nullptr, "etmain", "Wolfenstein: Enemy Territory", GEN_GAME_INFO(WET), 13, 5 }, + { "qagame" MP_DLL X64_DLL, "vm/qagame.mp.qvm", "main", "Return to Castle Wolfenstein (MP)", GEN_GAME_INFO(RTCWMP), 13, 5 }, // these games don't appear to have an official 64-bit version or source port #if defined(QMM_ARCH_32) - { "qagame" MOD_DLL, "vm/qagame.qvm", "baseef", "Star Trek Voyager: Elite Force (Holomatch)", GEN_INFO(STVOYHM), 13, 3 }, - { "sof2mp_game" MOD_DLL, "vm/sof2mp_game.qvm","base/mp", "Soldier of Fortune 2: Double Helix (MP)", GEN_INFO(SOF2MP), 13, 6 }, - { "game" MP_DLL MOD_DLL, nullptr, "Main", "Call of Duty (MP)", GEN_INFO(CODMP), 8, 4 }, - { "" UO_DLL MOD_DLL, nullptr, "uo", "Call of Duty: United Offensive (MP)", GEN_INFO(CODUOMP), 8, 4 }, + { "qagame" MOD_DLL, "vm/qagame.qvm", "baseef", "Star Trek Voyager: Elite Force (Holomatch)", GEN_GAME_INFO(STVOYHM), 13, 3 }, + { "sof2mp_game" MOD_DLL, "vm/sof2mp_game.qvm","base/mp", "Soldier of Fortune 2: Double Helix (MP)", GEN_GAME_INFO(SOF2MP), 13, 6 }, + { "game" MP_DLL MOD_DLL, nullptr, "Main", "Call of Duty (MP)", GEN_GAME_INFO(CODMP), 8, 4 }, + { "" UO_DLL MOD_DLL, nullptr, "uo", "Call of Duty: United Offensive (MP)", GEN_GAME_INFO(CODUOMP), 8, 4 }, // allow a user to choose "COD11MP" manually if they are playing an old version of CoD (no auto-detection) - { "game" MP_DLL MOD_DLL, nullptr, "Main", "Call of Duty v1.1 (MP)", GEN_INFO(COD11MP), 8, 4 }, + { "game" MP_DLL MOD_DLL, nullptr, "Main", "Call of Duty v1.1 (MP)", GEN_GAME_INFO(COD11MP), 8, 4 }, #endif // GetGameAPI games - { "jk2game" MOD_DLL, nullptr, ".", "Jedi Knight 2: Jedi Outcast (SP)", GEN_INFO(JK2SP), 13, 9 }, - { "jagame" MOD_DLL, nullptr, ".", "Jedi Knight: Jedi Academy (SP)", GEN_INFO(JASP), 13, 9 }, - { "game" MOD_DLL, nullptr, "baseq2", "Quake 2", GEN_INFO(QUAKE2), 7, 3 }, - { "game" MOD_DLL, nullptr, "base", "SiN", GEN_INFO(SIN), 10, 3 }, + { "jk2game" MOD_DLL, nullptr, ".", "Jedi Knight 2: Jedi Outcast (SP)", GEN_GAME_INFO(JK2SP), 13, 9 }, + { "jagame" MOD_DLL, nullptr, ".", "Jedi Knight: Jedi Academy (SP)", GEN_GAME_INFO(JASP), 13, 9 }, + { "game" MOD_DLL, nullptr, "baseq2", "Quake 2", GEN_GAME_INFO(QUAKE2), 7, 3 }, + { "game" MOD_DLL, nullptr, "base", "SiN", GEN_GAME_INFO(SIN), 10, 3 }, // OpenMOHAA adds 64-bit MoH support but the API is very different, so disable it for now // the rest of the games don't appear to have an official 64-bit version or source port #if defined(QMM_ARCH_32) - { "game" MOD_DLL, nullptr, "main", "Medal of Honor: Allied Assault", GEN_INFO(MOHAA), 9, 7 }, - { "game" MOD_DLL, nullptr, "mainta", "Medal of Honor: Spearhead", GEN_INFO(MOHSH), 9, 7 }, - { "game" MOD_DLL, nullptr, "maintt", "Medal of Honor: Breakthrough", GEN_INFO(MOHBT), 9, 7 }, - { "game" MOD_DLL, nullptr, "base", "Star Trek: Elite Force II", GEN_INFO(STEF2), 17, 4 }, - { "game" MOD_DLL, nullptr, ".", "Soldier of Fortune 2: Double Helix (SP)", GEN_INFO(SOF2SP), 0, 0 }, - { "efgame" MOD_DLL, nullptr, ".", "Star Trek Voyager: Elite Force (SP)", GEN_INFO(STVOYSP), 13, 9 }, + { "game" MOD_DLL, nullptr, "main", "Medal of Honor: Allied Assault", GEN_GAME_INFO(MOHAA), 9, 7 }, + { "game" MOD_DLL, nullptr, "mainta", "Medal of Honor: Spearhead", GEN_GAME_INFO(MOHSH), 9, 7 }, + { "game" MOD_DLL, nullptr, "maintt", "Medal of Honor: Breakthrough", GEN_GAME_INFO(MOHBT), 9, 7 }, + { "game" MOD_DLL, nullptr, "base", "Star Trek: Elite Force II", GEN_GAME_INFO(STEF2), 17, 4 }, + { "game" MOD_DLL, nullptr, ".", "Soldier of Fortune 2: Double Helix (SP)", GEN_GAME_INFO(SOF2SP), 0, 0 }, + { "efgame" MOD_DLL, nullptr, ".", "Star Trek Voyager: Elite Force (SP)", GEN_GAME_INFO(STVOYSP), 13, 9 }, #endif - // Q2R only exists for 64-bit Windows +// Q2R only exists for 64-bit Windows #if defined(QMM_OS_WINDOWS) && defined(QMM_ARCH_64) - { "game_x64.dll", nullptr, "baseq2", "Quake 2 Remastered", GEN_INFO(Q2R), 9, 6 }, + { "game_x64.dll", nullptr, "baseq2", "Quake 2 Remastered", GEN_GAME_INFO(Q2R), 9, 6 }, #endif }; + + +const char* APIType_Name(APIType api) { + switch (api) { + GEN_CASE(QMM_API_ERROR); + + GEN_CASE(QMM_API_QVM); + + GEN_CASE(QMM_API_DLLENTRY); + GEN_CASE(QMM_API_GETGAMEAPI); + GEN_CASE(QMM_API_GETMODULEAPI); + default: + return "unknown"; + }; +} + + +const char* APIType_Function(APIType api) { + switch (api) { + case QMM_API_ERROR: + return "(error)"; + + case QMM_API_QVM: + return "QVM"; + case QMM_API_DLLENTRY: + return "dllEntry"; + case QMM_API_GETGAMEAPI: + return "GetGameAPI"; + case QMM_API_GETMODULEAPI: + return "GetModuleAPI"; + default: + return "unknown"; + }; +} diff --git a/src/game_cod11mp.cpp b/src/game_cod11mp.cpp index d8ebb6a..b022891 100644 --- a/src/game_cod11mp.cpp +++ b/src/game_cod11mp.cpp @@ -18,14 +18,14 @@ Created By: #include "game_cod11mp.h" #include "main.h" -GEN_QMM_MSGS(COD11MP); -GEN_EXTS(COD11MP); +GEN_GAME_QMM_MSGS(COD11MP); +GEN_GAME_EXTS(COD11MP); -GEN_DLL(COD11MP); +GEN_GAME_FUNCS(COD11MP); // auto-detection logic for COD11MP (never auto-detect) -static bool COD11MP_autodetect(bool, supportedgame*) { +static bool COD11MP_AutoDetect(api_supportedgame*, APIType) { return false; } @@ -43,7 +43,7 @@ static intptr_t COD11MP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_syscall({} {}) called\n", COD11MP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_syscall({} {}) called\n", COD11MP_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -68,7 +68,7 @@ static intptr_t COD11MP_syscall(intptr_t cmd, ...) { } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } @@ -76,7 +76,7 @@ static intptr_t COD11MP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_syscall({} {}) returning {}\n", COD11MP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_syscall({} {}) returning {}\n", COD11MP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -89,7 +89,7 @@ static intptr_t COD11MP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_vmMain({} {}) called\n", COD11MP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_vmMain({} {}) called\n", COD11MP_ModMsgNames(cmd), cmd); #endif if (!orig_vmMain) @@ -102,18 +102,18 @@ static intptr_t COD11MP_vmMain(intptr_t cmd, ...) { ret = orig_vmMain(cmd, QMM_PUT_VMMAIN_ARGS()); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_vmMain({} {}) returning {}\n", COD11MP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_vmMain({} {}) returning {}\n", COD11MP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void COD11MP_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_dllEntry({}) called\n", (void*)syscall); +static void* COD11MP_Entry(void* syscall, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_Entry({}) called\n", syscall); // store original syscall from engine - orig_syscall = syscall; + orig_syscall = (eng_syscall)syscall; // pointer to wrapper vmMain function that calls actual mod vmMain func orig_vmMain g_gameinfo.pfnvmMain = COD11MP_vmMain; @@ -121,23 +121,28 @@ static void COD11MP_dllEntry(eng_syscall syscall) { // pointer to wrapper syscall function that calls actual engine syscall func g_gameinfo.pfnsyscall = COD11MP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_dllEntry({}) returning\n", (void*)syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_Entry({}) returning\n", syscall); + + return nullptr; } -static bool COD11MP_mod_load(void* entry, bool) { +static bool COD11MP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_DLLENTRY) + return false; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } -static void COD11MP_mod_unload() { +static void COD11MP_ModUnload() { orig_vmMain = nullptr; } -static const char* COD11MP_eng_msg_names(intptr_t cmd) { +static const char* COD11MP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_ERROR); @@ -284,7 +289,7 @@ static const char* COD11MP_eng_msg_names(intptr_t cmd) { } -static const char* COD11MP_mod_msg_names(intptr_t cmd) { +static const char* COD11MP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_INIT); GEN_CASE(GAME_SHUTDOWN); diff --git a/src/game_codmp.cpp b/src/game_codmp.cpp index c63cae8..4b40c22 100644 --- a/src/game_codmp.cpp +++ b/src/game_codmp.cpp @@ -23,16 +23,16 @@ Created By: // don't want to make plugins have to use separate code to handle the actual GAME_INIT message, so just // do a dirty redefine here for the QMM_GAME_INIT message definition #define GAME_INIT GAME_GET_APIVERSION -GEN_QMM_MSGS(CODMP); +GEN_GAME_QMM_MSGS(CODMP); #undef GAME_INIT -GEN_EXTS(CODMP); +GEN_GAME_EXTS(CODMP); -GEN_DLL(CODMP); +GEN_GAME_FUNCS(CODMP); // auto-detection logic for CODMP -static bool CODMP_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (is_GetGameAPI) +static bool CODMP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_DLLENTRY) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -58,7 +58,7 @@ static intptr_t CODMP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_syscall({} {}) called\n", CODMP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_syscall({} {}) called\n", CODMP_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -83,7 +83,7 @@ static intptr_t CODMP_syscall(intptr_t cmd, ...) { } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } @@ -91,7 +91,7 @@ static intptr_t CODMP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_syscall({} {}) returning {}\n", CODMP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_syscall({} {}) returning {}\n", CODMP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -104,7 +104,7 @@ static intptr_t CODMP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_vmMain({} {}) called\n", CODMP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_vmMain({} {}) called\n", CODMP_ModMsgNames(cmd), cmd); #endif if (!orig_vmMain) @@ -117,18 +117,18 @@ static intptr_t CODMP_vmMain(intptr_t cmd, ...) { ret = orig_vmMain(cmd, QMM_PUT_VMMAIN_ARGS()); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_vmMain({} {}) returning {}\n", CODMP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_vmMain({} {}) returning {}\n", CODMP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void CODMP_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_dllEntry({}) called\n", (void*)syscall); +static void* CODMP_Entry(void* syscall, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_Entry({}) called\n", syscall); // store original syscall from engine - orig_syscall = syscall; + orig_syscall = (eng_syscall)syscall; // pointer to wrapper vmMain function that calls actual mod vmMain func orig_vmMain g_gameinfo.pfnvmMain = CODMP_vmMain; @@ -136,23 +136,28 @@ static void CODMP_dllEntry(eng_syscall syscall) { // pointer to wrapper syscall function that calls actual engine syscall func g_gameinfo.pfnsyscall = CODMP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_dllEntry({}) returning\n", (void*)syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_Entry({}) returning\n", syscall); + + return nullptr; } -static bool CODMP_mod_load(void* entry, bool) { +static bool CODMP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_DLLENTRY) + return false; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } -static void CODMP_mod_unload() { +static void CODMP_ModUnload() { orig_vmMain = nullptr; } -static const char* CODMP_eng_msg_names(intptr_t cmd) { +static const char* CODMP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_ERROR); @@ -304,7 +309,7 @@ static const char* CODMP_eng_msg_names(intptr_t cmd) { } -static const char* CODMP_mod_msg_names(intptr_t cmd) { +static const char* CODMP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_DEFAULT_0); GEN_CASE(GAME_GET_APIVERSION); diff --git a/src/game_coduomp.cpp b/src/game_coduomp.cpp index 21eba54..a9c9aca 100644 --- a/src/game_coduomp.cpp +++ b/src/game_coduomp.cpp @@ -23,16 +23,16 @@ Created By: // don't want to make plugins have to use separate code to handle the actual GAME_INIT message, so just // do a dirty redefine here for the QMM_GAME_INIT message definition #define GAME_INIT GAME_GET_APIVERSION -GEN_QMM_MSGS(CODUOMP); +GEN_GAME_QMM_MSGS(CODUOMP); #undef GAME_INIT -GEN_EXTS(CODUOMP); +GEN_GAME_EXTS(CODUOMP); -GEN_DLL(CODUOMP); +GEN_GAME_FUNCS(CODUOMP); // auto-detection logic for CODUOMP -static bool CODUOMP_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (is_GetGameAPI) +static bool CODUOMP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_DLLENTRY) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -58,7 +58,7 @@ static intptr_t CODUOMP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_syscall({} {}) called\n", CODUOMP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_syscall({} {}) called\n", CODUOMP_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -83,7 +83,7 @@ static intptr_t CODUOMP_syscall(intptr_t cmd, ...) { } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } @@ -91,7 +91,7 @@ static intptr_t CODUOMP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_syscall({} {}) returning {}\n", CODUOMP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_syscall({} {}) returning {}\n", CODUOMP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -104,7 +104,7 @@ static intptr_t CODUOMP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_vmMain({} {}) called\n", CODUOMP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_vmMain({} {}) called\n", CODUOMP_ModMsgNames(cmd), cmd); #endif if (!orig_vmMain) @@ -117,18 +117,18 @@ static intptr_t CODUOMP_vmMain(intptr_t cmd, ...) { ret = orig_vmMain(cmd, QMM_PUT_VMMAIN_ARGS()); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_vmMain({} {}) returning {}\n", CODUOMP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_vmMain({} {}) returning {}\n", CODUOMP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void CODUOMP_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_dllEntry({}) called\n", (void*)syscall); +static void* CODUOMP_Entry(void* syscall, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_Entry({}) called\n", syscall); // store original syscall from engine - orig_syscall = syscall; + orig_syscall = (eng_syscall)syscall; // pointer to wrapper vmMain function that calls actual mod vmMain func orig_vmMain g_gameinfo.pfnvmMain = CODUOMP_vmMain; @@ -136,23 +136,28 @@ static void CODUOMP_dllEntry(eng_syscall syscall) { // pointer to wrapper syscall function that calls actual engine syscall func g_gameinfo.pfnsyscall = CODUOMP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_dllEntry({}) returning\n", (void*)syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_Entry({}) returning\n", syscall); + + return nullptr; } -static bool CODUOMP_mod_load(void* entry, bool) { +static bool CODUOMP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_DLLENTRY) + return false; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } -static void CODUOMP_mod_unload() { +static void CODUOMP_ModUnload() { orig_vmMain = nullptr; } -static const char* CODUOMP_eng_msg_names(intptr_t cmd) { +static const char* CODUOMP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_ERROR); @@ -304,7 +309,7 @@ static const char* CODUOMP_eng_msg_names(intptr_t cmd) { } -static const char* CODUOMP_mod_msg_names(intptr_t cmd) { +static const char* CODUOMP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_DEFAULT_0); GEN_CASE(GAME_GET_APIVERSION); diff --git a/src/game_jamp.cpp b/src/game_jamp.cpp index cd50b90..218bd35 100644 --- a/src/game_jamp.cpp +++ b/src/game_jamp.cpp @@ -20,43 +20,31 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(JAMP); -GEN_EXTS(JAMP); - -// do not use macro since this game supports both dllEntry and GetGameAPI entry points -static const char* JAMP_eng_msg_names(intptr_t); -static const char* JAMP_mod_msg_names(intptr_t); -static bool JAMP_autodetect(bool, supportedgame*); -static intptr_t JAMP_syscall(intptr_t cmd, ...); -static intptr_t JAMP_vmMain(intptr_t cmd, ...); -static void JAMP_dllEntry(eng_syscall); -static void* JAMP_GetGameAPI(void*, void*); -static bool JAMP_mod_load(void*, bool); -static void JAMP_mod_unload(); -supportedgame_funcs JAMP_funcs = { - JAMP_qmm_eng_msgs, - JAMP_qmm_mod_msgs, - JAMP_eng_msg_names, - JAMP_mod_msg_names, - JAMP_autodetect, - nullptr, // JAMP_qvmsyscall - JAMP_dllEntry, - JAMP_GetGameAPI, - JAMP_mod_load, - JAMP_mod_unload, -}; +GEN_GAME_QMM_MSGS(JAMP); +GEN_GAME_EXTS(JAMP); + +GEN_GAME_FUNCS(JAMP); // auto-detection logic for JAMP -static bool JAMP_autodetect(bool is_GetGameAPI, supportedgame* game) { +static bool JAMP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_DLLENTRY && engineapi != QMM_API_GETMODULEAPI) + return false; + // QMM filename must match default or an OpenJK temp filename (if DLL was pulled from .pk3) if (!str_striequal(g_gameinfo.qmm_file, game->dllname) && !str_striequal(g_gameinfo.qmm_file.substr(0, 3), "ojk") && !str_striequal(path_baseext(g_gameinfo.qmm_file), "tmp")) + { return false; + } - if (!str_stristr(g_gameinfo.exe_file, "jamp") && !str_stristr(g_gameinfo.exe_file, "openjk.") && !str_stristr(g_gameinfo.exe_file, "openjkded")) + if (!str_stristr(g_gameinfo.exe_file, "jamp") + && !str_stristr(g_gameinfo.exe_file, "openjk.") + && !str_stristr(g_gameinfo.exe_file, "openjkded")) + { return false; + } return true; } @@ -445,13 +433,13 @@ static intptr_t JAMP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_syscall({} {}) called\n", JAMP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_syscall({} {}) called\n", JAMP_EngMsgNames(cmd), cmd); #endif // store return value since we do some stuff after the function call is over intptr_t ret = 0; - // if QMM was loaded with the official JAMP or OpenJK "legacy" API (which shouldn't happen, but whatever) + // if QMM was loaded with the official JAMP or OpenJK "legacy" API if (orig_syscall) { switch (cmd) { // handle special cmds which QMM uses but JAMP doesn't have an analogue for @@ -473,7 +461,7 @@ static intptr_t JAMP_syscall(intptr_t cmd, ...) { } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } } @@ -817,7 +805,7 @@ static intptr_t JAMP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_syscall({} {}) returning {}\n", JAMP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_syscall({} {}) returning {}\n", JAMP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -830,18 +818,18 @@ static intptr_t JAMP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_vmMain({} {}) called\n", JAMP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_vmMain({} {}) called\n", JAMP_ModMsgNames(cmd), cmd); #endif // store return value since we do some stuff after the function call is over intptr_t ret = 0; - // if QMM was loaded with the official JAMP or OpenJK "legacy" API (which shouldn't happen, but whatever) + // if the loaded JAMP mod uses the official JAMP or OpenJK "legacy" API if (orig_vmMain) { // all normal mod functions go to mod ret = orig_vmMain(cmd, QMM_PUT_VMMAIN_ARGS()); } - // if QMM was loaded with the OpenJK "new" API + // if the loaded JAMP mod uses the OpenJK "new" API else if (orig_export) { switch (cmd) { ROUTE_EXPORT(InitGame, GAME_INIT); @@ -891,78 +879,83 @@ static intptr_t JAMP_vmMain(intptr_t cmd, ...) { } #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_vmMain({} {}) returning {}\n", JAMP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_vmMain({} {}) returning {}\n", JAMP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void JAMP_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_dllEntry({}) called\n", (void*)syscall); - - // store original syscall from engine - orig_syscall = syscall; +static void* JAMP_Entry(void* arg0, void* arg1, APIType engine) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_Entry({}, {}, {}) called\n", arg0, arg1, APIType_Name(engine)); - // pointer to wrapper vmMain function that calls either orig_vmMain or func in orig_export - g_gameinfo.pfnvmMain = JAMP_vmMain; + if (engine == QMM_API_GETMODULEAPI) { + orig_apiversion = (intptr_t)arg0; - // pointer to wrapper syscall function that calls either orig_syscall or func in orig_import - g_gameinfo.pfnsyscall = JAMP_syscall; + // original import struct from engine + // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing + game_import_t* gi = (game_import_t*)arg1; + orig_import = *gi; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_dllEntry({}) returning\n", (void*)syscall); -} + // fill in variables of our hooked import struct to pass to the mod + // pointer to wrapper vmMain function that calls either orig_vmMain or func in orig_export + g_gameinfo.pfnvmMain = JAMP_vmMain; -static void* JAMP_GetGameAPI(void* apiversion, void* import) { - orig_apiversion = (intptr_t)apiversion; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_GetGameAPI({}, {}) called\n", orig_apiversion, import); + // pointer to wrapper syscall function that calls either orig_syscall or func in orig_import + g_gameinfo.pfnsyscall = JAMP_syscall; - // original import struct from engine - // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing - game_import_t* gi = (game_import_t*)import; - orig_import = *gi; + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_Entry({}, {}, {}) returning {}\n", arg0, arg1, APIType_Name(engine), (void*)&qmm_export); - // fill in variables of our hooked import struct to pass to the mod + // struct full of export lambdas to QMM's vmMain + // this gets returned to the game engine, but we haven't loaded the mod yet. + return &qmm_export; + } + else if (engine == QMM_API_DLLENTRY) { + // store original syscall from engine + orig_syscall = (eng_syscall)arg0; - // pointer to wrapper vmMain function that calls either orig_vmMain or func in orig_export - g_gameinfo.pfnvmMain = JAMP_vmMain; + // pointer to wrapper vmMain function that calls either orig_vmMain or func in orig_export + g_gameinfo.pfnvmMain = JAMP_vmMain; - // pointer to wrapper syscall function that calls either orig_syscall or func in orig_import - g_gameinfo.pfnsyscall = JAMP_syscall; + // pointer to wrapper syscall function that calls either orig_syscall or func in orig_import + g_gameinfo.pfnsyscall = JAMP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_GetGameAPI({}, {}) returning {}\n", orig_apiversion, import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_Entry({}, {}, {}) returning\n", arg0, arg1, APIType_Name(engine)); - // struct full of export lambdas to QMM's vmMain - // this gets returned to the game engine, but we haven't loaded the mod yet. - // the only thing in this struct the engine uses before calling Init is the apiversion - return &qmm_export; + return nullptr; + } + return nullptr; } -static bool JAMP_mod_load(void* entry, bool is_GetGameAPI) { - if (is_GetGameAPI) { +static bool JAMP_ModLoad(void* entry, APIType modapi) { + if (modapi == QMM_API_GETMODULEAPI) { mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; // api version gets passed before import pointer + // if QMM was loaded with dllEntry, then orig_apiversion is 0 so try to get it from SDK + if (orig_syscall || !orig_apiversion) + orig_apiversion = GAME_API_VERSION; orig_export = (game_export_t*)pfnGGA((void*)orig_apiversion, &qmm_import); return !!orig_export; } - else { + else if (modapi == QMM_API_DLLENTRY) { orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } + return false; } -static void JAMP_mod_unload() { +static void JAMP_ModUnload() { orig_export = nullptr; orig_vmMain = nullptr; } -static const char* JAMP_eng_msg_names(intptr_t cmd) { +static const char* JAMP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINT); GEN_CASE(G_ERROR); @@ -1303,7 +1296,7 @@ static const char* JAMP_eng_msg_names(intptr_t cmd) { } -static const char* JAMP_mod_msg_names(intptr_t cmd) { +static const char* JAMP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_INIT); GEN_CASE(GAME_SHUTDOWN); diff --git a/src/game_jasp.cpp b/src/game_jasp.cpp index a92909b..cda382d 100644 --- a/src/game_jasp.cpp +++ b/src/game_jasp.cpp @@ -22,15 +22,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(JASP); -GEN_EXTS(JASP); +GEN_GAME_QMM_MSGS(JASP); +GEN_GAME_EXTS(JASP); -GEN_GGA(JASP); +GEN_GAME_FUNCS(JASP); // auto-detection logic for JASP -static bool JASP_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool JASP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -262,7 +262,7 @@ static intptr_t JASP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_syscall({} {}) called\n", JASP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_syscall({} {}) called\n", JASP_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -492,7 +492,7 @@ static intptr_t JASP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_syscall({} {}) returning {}\n", JASP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_syscall({} {}) returning {}\n", JASP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -505,7 +505,7 @@ static intptr_t JASP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_vmMain({} {}) called\n", JASP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_vmMain({} {}) called\n", JASP_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -545,15 +545,15 @@ static intptr_t JASP_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_vmMain({} {}) returning {}\n", JASP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_vmMain({} {}) returning {}\n", JASP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* JASP_GetGameAPI(void* import, void*) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_GetGameAPI({}) called\n", import); +static void* JASP_Entry(void* import, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_Entry({}) called\n", import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -569,7 +569,7 @@ static void* JASP_GetGameAPI(void* import, void*) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = JASP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_GetGameAPI({}) returning {}\n", import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JASP_Entry({}) returning {}\n", import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -578,7 +578,10 @@ static void* JASP_GetGameAPI(void* import, void*) { } -static bool JASP_mod_load(void* entry, bool) { +static bool JASP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); @@ -586,12 +589,12 @@ static bool JASP_mod_load(void* entry, bool) { } -static void JASP_mod_unload() { +static void JASP_ModUnload() { orig_export = nullptr; } -static const char* JASP_eng_msg_names(intptr_t cmd) { +static const char* JASP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_WRITECAM); @@ -737,7 +740,7 @@ static const char* JASP_eng_msg_names(intptr_t cmd) { } -static const char* JASP_mod_msg_names(intptr_t cmd) { +static const char* JASP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAMEV_APIVERSION); GEN_CASE(GAME_INIT); diff --git a/src/game_jk2mp.cpp b/src/game_jk2mp.cpp index c38a502..844220f 100644 --- a/src/game_jk2mp.cpp +++ b/src/game_jk2mp.cpp @@ -21,15 +21,15 @@ Created By: #include "mod.h" #include "util.h" -GEN_QMM_MSGS(JK2MP); -GEN_EXTS(JK2MP); +GEN_GAME_QMM_MSGS(JK2MP); +GEN_GAME_EXTS(JK2MP); -GEN_DLLQVM(JK2MP); +GEN_GAME_FUNCS_QVM(JK2MP); // auto-detection logic for JK2MP -static bool JK2MP_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (is_GetGameAPI) +static bool JK2MP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_DLLENTRY) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -55,7 +55,7 @@ static intptr_t JK2MP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_syscall({} {}) called\n", JK2MP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_syscall({} {}) called\n", JK2MP_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -80,7 +80,7 @@ static intptr_t JK2MP_syscall(intptr_t cmd, ...) { } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } @@ -88,7 +88,7 @@ static intptr_t JK2MP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_syscall({} {}) returning {}\n", JK2MP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_syscall({} {}) returning {}\n", JK2MP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -101,7 +101,7 @@ static intptr_t JK2MP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_vmMain({} {}) called\n", JK2MP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_vmMain({} {}) called\n", JK2MP_ModMsgNames(cmd), cmd); #endif if (!orig_vmMain) @@ -120,18 +120,18 @@ static intptr_t JK2MP_vmMain(intptr_t cmd, ...) { } #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_vmMain({} {}) returning {}\n", JK2MP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_vmMain({} {}) returning {}\n", JK2MP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void JK2MP_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_dllEntry({}) called\n", (void*)syscall); +static void* JK2MP_Entry(void* syscall, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_Entry({}) called\n", syscall); // store original syscall from engine - orig_syscall = syscall; + orig_syscall = (eng_syscall)syscall; // pointer to wrapper vmMain function that calls actual mod vmMain func orig_vmMain g_gameinfo.pfnvmMain = JK2MP_vmMain; @@ -139,23 +139,28 @@ static void JK2MP_dllEntry(eng_syscall syscall) { // pointer to wrapper syscall function that calls actual engine syscall func g_gameinfo.pfnsyscall = JK2MP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_dllEntry({}) returning\n", (void*)syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_Entry({}) returning\n", syscall); + + return nullptr; } -static bool JK2MP_mod_load(void* entry, bool) { +static bool JK2MP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_DLLENTRY && modapi != QMM_API_QVM) + return false; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } -static void JK2MP_mod_unload() { +static void JK2MP_ModUnload() { orig_vmMain = nullptr; } -static const char* JK2MP_eng_msg_names(intptr_t cmd) { +static const char* JK2MP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINT); GEN_CASE(G_ERROR); @@ -394,7 +399,7 @@ static const char* JK2MP_eng_msg_names(intptr_t cmd) { } -static const char* JK2MP_mod_msg_names(intptr_t cmd) { +static const char* JK2MP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_INIT); GEN_CASE(GAME_SHUTDOWN); @@ -422,9 +427,9 @@ static const char* JK2MP_mod_msg_names(intptr_t cmd) { // vec3_t are arrays, so convert them as pointers // do NOT convert the "ghoul" void pointers, treat them as plain ints // for double pointers (gentity_t**, vec3_t*, void**), convert them once with vmptr() -int JK2MP_qvmsyscall(uint8_t* membase, int cmd, int* args) { +int JK2MP_QVMSyscall(uint8_t* membase, int cmd, int* args) { #ifdef _DEBUG - LOG(QMM_LOG_TRACE, "QMM") << fmt::format("JK2MP_qvmsyscall({} {}) called\n", JK2MP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_TRACE, "QMM") << fmt::format("JK2MP_QVMSyscall({} {}) called\n", JK2MP_EngMsgNames(cmd), cmd); #endif int ret = 0; @@ -749,7 +754,7 @@ int JK2MP_qvmsyscall(uint8_t* membase, int cmd, int* args) { } #ifdef _DEBUG - LOG(QMM_LOG_TRACE, "QMM") << fmt::format("JK2MP_qvmsyscall({} {}) returning {}\n", JK2MP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_TRACE, "QMM") << fmt::format("JK2MP_QVMSyscall({} {}) returning {}\n", JK2MP_EngMsgNames(cmd), cmd, ret); #endif return ret; diff --git a/src/game_jk2sp.cpp b/src/game_jk2sp.cpp index 64a6555..a9c582a 100644 --- a/src/game_jk2sp.cpp +++ b/src/game_jk2sp.cpp @@ -21,15 +21,15 @@ Created By: #include "util.h" -GEN_QMM_MSGS(JK2SP); -GEN_EXTS(JK2SP); +GEN_GAME_QMM_MSGS(JK2SP); +GEN_GAME_EXTS(JK2SP); -GEN_GGA(JK2SP); +GEN_GAME_FUNCS(JK2SP); // auto-detection logic for JK2SP -static bool JK2SP_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool JK2SP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -231,7 +231,7 @@ static intptr_t JK2SP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_syscall({} {}) called\n", JK2SP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_syscall({} {}) called\n", JK2SP_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -413,7 +413,7 @@ static intptr_t JK2SP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_syscall({} {}) returning {}\n", JK2SP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_syscall({} {}) returning {}\n", JK2SP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -426,7 +426,7 @@ static intptr_t JK2SP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_vmMain({} {}) called\n", JK2SP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_vmMain({} {}) called\n", JK2SP_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -466,15 +466,15 @@ static intptr_t JK2SP_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_vmMain({} {}) returning {}\n", JK2SP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_vmMain({} {}) returning {}\n", JK2SP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* JK2SP_GetGameAPI(void* import, void*) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_GetGameAPI({}) called\n", import); +static void* JK2SP_Entry(void* import, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_Entry({}) called\n", import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -490,7 +490,7 @@ static void* JK2SP_GetGameAPI(void* import, void*) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = JK2SP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_GetGameAPI({}) returning {}\n", import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2SP_Entry({}) returning {}\n", import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -499,7 +499,10 @@ static void* JK2SP_GetGameAPI(void* import, void*) { } -static bool JK2SP_mod_load(void* entry, bool) { +static bool JK2SP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); @@ -507,12 +510,12 @@ static bool JK2SP_mod_load(void* entry, bool) { } -static void JK2SP_mod_unload() { +static void JK2SP_ModUnload() { orig_export = nullptr; } -static const char* JK2SP_eng_msg_names(intptr_t cmd) { +static const char* JK2SP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_WRITECAM); @@ -630,7 +633,7 @@ static const char* JK2SP_eng_msg_names(intptr_t cmd) { } -static const char* JK2SP_mod_msg_names(intptr_t cmd) { +static const char* JK2SP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAMEV_APIVERSION); GEN_CASE(GAME_INIT); diff --git a/src/game_mohaa.cpp b/src/game_mohaa.cpp index 785ca36..e60dc27 100644 --- a/src/game_mohaa.cpp +++ b/src/game_mohaa.cpp @@ -26,15 +26,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(MOHAA); -GEN_EXTS(MOHAA); +GEN_GAME_QMM_MSGS(MOHAA); +GEN_GAME_EXTS(MOHAA); -GEN_GGA(MOHAA); +GEN_GAME_FUNCS(MOHAA); // auto-detection logic for MOHAA -static bool MOHAA_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool MOHAA_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -334,7 +334,7 @@ static intptr_t MOHAA_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_syscall({} {}) called\n", MOHAA_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_syscall({} {}) called\n", MOHAA_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -661,7 +661,7 @@ static intptr_t MOHAA_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_syscall({} {}) returning {}\n", MOHAA_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_syscall({} {}) returning {}\n", MOHAA_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -674,7 +674,7 @@ static intptr_t MOHAA_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_vmMain({} {}) called\n", MOHAA_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_vmMain({} {}) called\n", MOHAA_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -736,15 +736,15 @@ static intptr_t MOHAA_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_vmMain({} {}) returning {}\n", MOHAA_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_vmMain({} {}) returning {}\n", MOHAA_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* MOHAA_GetGameAPI(void* import, void*) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_GetGameAPI({}) called\n", import); +static void* MOHAA_Entry(void* import, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_Entry({}) called\n", import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -764,7 +764,7 @@ static void* MOHAA_GetGameAPI(void* import, void*) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = MOHAA_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_GetGameAPI({}) returning {}\n", import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHAA_Entry({}) returning {}\n", import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -773,7 +773,10 @@ static void* MOHAA_GetGameAPI(void* import, void*) { } -static bool MOHAA_mod_load(void* entry, bool) { +static bool MOHAA_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); @@ -781,12 +784,12 @@ static bool MOHAA_mod_load(void* entry, bool) { } -static void MOHAA_mod_unload() { +static void MOHAA_ModUnload() { orig_export = nullptr; } -static const char* MOHAA_eng_msg_names(intptr_t cmd) { +static const char* MOHAA_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_DPRINTF); @@ -968,7 +971,7 @@ static const char* MOHAA_eng_msg_names(intptr_t cmd) { } -static const char* MOHAA_mod_msg_names(intptr_t cmd) { +static const char* MOHAA_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAMEV_APIVERSION); GEN_CASE(GAME_INIT); diff --git a/src/game_mohbt.cpp b/src/game_mohbt.cpp index 37a4a74..a78cbbb 100644 --- a/src/game_mohbt.cpp +++ b/src/game_mohbt.cpp @@ -26,15 +26,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(MOHBT); -GEN_EXTS(MOHBT); +GEN_GAME_QMM_MSGS(MOHBT); +GEN_GAME_EXTS(MOHBT); -GEN_GGA(MOHBT); +GEN_GAME_FUNCS(MOHBT); // auto-detection logic for MOHBT -static bool MOHBT_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool MOHBT_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -342,7 +342,7 @@ static intptr_t MOHBT_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_syscall({} {}) called\n", MOHBT_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_syscall({} {}) called\n", MOHBT_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -700,7 +700,7 @@ static intptr_t MOHBT_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_syscall({} {}) returning {}\n", MOHBT_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_syscall({} {}) returning {}\n", MOHBT_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -713,7 +713,7 @@ static intptr_t MOHBT_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_vmMain({} {}) called\n", MOHBT_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_vmMain({} {}) called\n", MOHBT_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -775,15 +775,15 @@ static intptr_t MOHBT_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_vmMain({} {}) returning {}\n", MOHBT_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_vmMain({} {}) returning {}\n", MOHBT_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* MOHBT_GetGameAPI(void* import, void*) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_GetGameAPI({}) called\n", import); +static void* MOHBT_Entry(void* import, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_Entry({}) called\n", import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -803,7 +803,7 @@ static void* MOHBT_GetGameAPI(void* import, void*) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = MOHBT_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_GetGameAPI({}) returning {}\n", import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHBT_Entry({}) returning {}\n", import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -812,7 +812,10 @@ static void* MOHBT_GetGameAPI(void* import, void*) { } -static bool MOHBT_mod_load(void* entry, bool) { +static bool MOHBT_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); @@ -820,12 +823,12 @@ static bool MOHBT_mod_load(void* entry, bool) { } -static void MOHBT_mod_unload() { +static void MOHBT_ModUnload() { orig_export = nullptr; } -static const char* MOHBT_eng_msg_names(intptr_t cmd) { +static const char* MOHBT_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_DPRINTF); @@ -1014,7 +1017,7 @@ static const char* MOHBT_eng_msg_names(intptr_t cmd) { } -static const char* MOHBT_mod_msg_names(intptr_t cmd) { +static const char* MOHBT_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAMEV_APIVERSION); GEN_CASE(GAME_INIT); diff --git a/src/game_mohsh.cpp b/src/game_mohsh.cpp index ce8d97d..3fdd689 100644 --- a/src/game_mohsh.cpp +++ b/src/game_mohsh.cpp @@ -26,15 +26,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(MOHSH); -GEN_EXTS(MOHSH); +GEN_GAME_QMM_MSGS(MOHSH); +GEN_GAME_EXTS(MOHSH); -GEN_GGA(MOHSH); +GEN_GAME_FUNCS(MOHSH); // auto-detection logic for MOHSH -static bool MOHSH_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool MOHSH_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -342,7 +342,7 @@ static intptr_t MOHSH_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_syscall({} {}) called\n", MOHSH_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_syscall({} {}) called\n", MOHSH_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -700,7 +700,7 @@ static intptr_t MOHSH_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_syscall({} {}) returning {}\n", MOHSH_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_syscall({} {}) returning {}\n", MOHSH_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -713,7 +713,7 @@ static intptr_t MOHSH_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_vmMain({} {}) called\n", MOHSH_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_vmMain({} {}) called\n", MOHSH_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -775,15 +775,15 @@ static intptr_t MOHSH_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_vmMain({} {}) returning {}\n", MOHSH_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_vmMain({} {}) returning {}\n", MOHSH_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* MOHSH_GetGameAPI(void* import, void*) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_GetGameAPI({}) called\n", import); +static void* MOHSH_Entry(void* import, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_Entry({}) called\n", import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -803,7 +803,7 @@ static void* MOHSH_GetGameAPI(void* import, void*) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = MOHSH_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_GetGameAPI({}) returning {}\n", import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("MOHSH_Entry({}) returning {}\n", import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -812,7 +812,10 @@ static void* MOHSH_GetGameAPI(void* import, void*) { } -static bool MOHSH_mod_load(void* entry, bool) { +static bool MOHSH_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); @@ -820,12 +823,12 @@ static bool MOHSH_mod_load(void* entry, bool) { } -static void MOHSH_mod_unload() { +static void MOHSH_ModUnload() { orig_export = nullptr; } -static const char* MOHSH_eng_msg_names(intptr_t cmd) { +static const char* MOHSH_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_DPRINTF); @@ -1014,7 +1017,7 @@ static const char* MOHSH_eng_msg_names(intptr_t cmd) { } -static const char* MOHSH_mod_msg_names(intptr_t cmd) { +static const char* MOHSH_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAMEV_APIVERSION); GEN_CASE(GAME_INIT); diff --git a/src/game_q2r.cpp b/src/game_q2r.cpp index bbb1f44..1644f74 100644 --- a/src/game_q2r.cpp +++ b/src/game_q2r.cpp @@ -34,16 +34,16 @@ Created By: // don't want to make plugins have to use separate code to handle the actual GAME_INIT message, so just // do a dirty redefine here for the QMM_GAME_INIT message definition #define GAME_INIT GAME_PREINIT -GEN_QMM_MSGS(Q2R); +GEN_GAME_QMM_MSGS(Q2R); #undef GAME_INIT -GEN_EXTS(Q2R); +GEN_GAME_EXTS(Q2R); -GEN_GGA(Q2R); +GEN_GAME_FUNCS(Q2R); // auto-detection logic for Q2R -static bool Q2R_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool Q2R_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -284,7 +284,7 @@ static intptr_t Q2R_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_syscall({} {}) called\n", Q2R_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_syscall({} {}) called\n", Q2R_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -523,7 +523,7 @@ static intptr_t Q2R_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_syscall({} {}) returning {}\n", Q2R_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_syscall({} {}) returning {}\n", Q2R_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -536,7 +536,7 @@ static intptr_t Q2R_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_vmMain({} {}) called\n", Q2R_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_vmMain({} {}) called\n", Q2R_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -591,15 +591,15 @@ static intptr_t Q2R_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_vmMain({} {}) returning {}\n", Q2R_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_vmMain({} {}) returning {}\n", Q2R_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* Q2R_GetGameAPI(void* import, void*) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_GetGameAPI({}) called\n", import); +static void* Q2R_Entry(void* import, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_Entry({}) called\n", import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -617,7 +617,7 @@ static void* Q2R_GetGameAPI(void* import, void*) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = Q2R_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_GetGameAPI({}) returning {}\n", import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q2R_Entry({}) returning {}\n", import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -626,7 +626,10 @@ static void* Q2R_GetGameAPI(void* import, void*) { } -static bool Q2R_mod_load(void* entry, bool) { +static bool Q2R_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); @@ -634,12 +637,12 @@ static bool Q2R_mod_load(void* entry, bool) { } -static void Q2R_mod_unload() { +static void Q2R_ModUnload() { orig_export = nullptr; } -static const char* Q2R_eng_msg_names(intptr_t cmd) { +static const char* Q2R_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_BROADCAST_PRINT); GEN_CASE(G_COM_PRINT); @@ -734,7 +737,7 @@ static const char* Q2R_eng_msg_names(intptr_t cmd) { } -static const char* Q2R_mod_msg_names(intptr_t cmd) { +static const char* Q2R_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAMEV_APIVERSION); GEN_CASE(GAME_PREINIT); diff --git a/src/game_q3a.cpp b/src/game_q3a.cpp index d90766a..11ef35c 100644 --- a/src/game_q3a.cpp +++ b/src/game_q3a.cpp @@ -21,15 +21,15 @@ Created By: #include "mod.h" #include "util.h" -GEN_QMM_MSGS(Q3A); -GEN_EXTS(Q3A); +GEN_GAME_QMM_MSGS(Q3A); +GEN_GAME_EXTS(Q3A); -GEN_DLLQVM(Q3A); +GEN_GAME_FUNCS_QVM(Q3A); // auto-detection logic for Q3A -static bool Q3A_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (is_GetGameAPI) +static bool Q3A_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_DLLENTRY) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -55,7 +55,7 @@ static intptr_t Q3A_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_syscall({} {}) called\n", Q3A_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_syscall({} {}) called\n", Q3A_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -79,7 +79,7 @@ static intptr_t Q3A_syscall(intptr_t cmd, ...) { break; } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } @@ -87,7 +87,7 @@ static intptr_t Q3A_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_syscall({} {}) returning {}\n", Q3A_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_syscall({} {}) returning {}\n", Q3A_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -100,7 +100,7 @@ static intptr_t Q3A_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_vmMain({} {}) called\n", Q3A_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_vmMain({} {}) called\n", Q3A_ModMsgNames(cmd), cmd); #endif if (!orig_vmMain) @@ -119,18 +119,18 @@ static intptr_t Q3A_vmMain(intptr_t cmd, ...) { } #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_vmMain({} {}) returning {}\n", Q3A_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_vmMain({} {}) returning {}\n", Q3A_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void Q3A_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_dllEntry({}) called\n", (void*)syscall); +static void* Q3A_Entry(void* syscall, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_Entry({}) called\n", syscall); // store original syscall from engine - orig_syscall = syscall; + orig_syscall = (eng_syscall)syscall; // pointer to wrapper vmMain function that calls actual mod vmMain func g_gameinfo.pfnvmMain = Q3A_vmMain; @@ -138,23 +138,28 @@ static void Q3A_dllEntry(eng_syscall syscall) { // pointer to wrapper syscall function that calls actual engine syscall func g_gameinfo.pfnsyscall = Q3A_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_dllEntry({}) returning\n", (void*)syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_Entry({}) returning\n", syscall); + + return nullptr; } -static bool Q3A_mod_load(void* entry, bool) { +static bool Q3A_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_DLLENTRY && modapi != QMM_API_QVM) + return false; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } -static void Q3A_mod_unload() { +static void Q3A_ModUnload() { orig_vmMain = nullptr; } -static const char* Q3A_eng_msg_names(intptr_t cmd) { +static const char* Q3A_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINT); GEN_CASE(G_ERROR); @@ -363,7 +368,7 @@ static const char* Q3A_eng_msg_names(intptr_t cmd) { } -static const char* Q3A_mod_msg_names(intptr_t cmd) { +static const char* Q3A_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_INIT); GEN_CASE(GAME_SHUTDOWN); @@ -389,9 +394,9 @@ static const char* Q3A_mod_msg_names(intptr_t cmd) { */ // vec3_t are arrays, so convert them as pointers // for double pointers (gentity_t** and vec3_t*), convert them once with vmptr() -static int Q3A_qvmsyscall(uint8_t* membase, int cmd, int* args) { +static int Q3A_QVMSyscall(uint8_t* membase, int cmd, int* args) { #ifdef _DEBUG - LOG(QMM_LOG_TRACE, "QMM") << fmt::format("Q3A_qvmsyscall({} {}) called\n", Q3A_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_TRACE, "QMM") << fmt::format("Q3A_QVMSyscall({} {}) called\n", Q3A_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -676,7 +681,7 @@ static int Q3A_qvmsyscall(uint8_t* membase, int cmd, int* args) { } #ifdef _DEBUG - LOG(QMM_LOG_TRACE, "QMM") << fmt::format("Q3A_qvmsyscall({} {}) returning {}\n", Q3A_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_TRACE, "QMM") << fmt::format("Q3A_QVMSyscall({} {}) returning {}\n", Q3A_EngMsgNames(cmd), cmd, ret); #endif return ret; diff --git a/src/game_quake2.cpp b/src/game_quake2.cpp index 7bfbb0d..be08e57 100644 --- a/src/game_quake2.cpp +++ b/src/game_quake2.cpp @@ -25,15 +25,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(QUAKE2); -GEN_EXTS(QUAKE2); +GEN_GAME_QMM_MSGS(QUAKE2); +GEN_GAME_EXTS(QUAKE2); -GEN_GGA(QUAKE2); +GEN_GAME_FUNCS(QUAKE2); // auto-detection logic for QUAKE2 -static bool QUAKE2_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool QUAKE2_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -227,7 +227,7 @@ static intptr_t QUAKE2_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_syscall({} {}) called\n", QUAKE2_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_syscall({} {}) called\n", QUAKE2_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -456,7 +456,7 @@ static intptr_t QUAKE2_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_syscall({} {}) returning {}\n", QUAKE2_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_syscall({} {}) returning {}\n", QUAKE2_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -469,7 +469,7 @@ static intptr_t QUAKE2_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_vmMain({} {}) called\n", QUAKE2_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_vmMain({} {}) called\n", QUAKE2_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -510,15 +510,15 @@ static intptr_t QUAKE2_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_vmMain({} {}) returning {}\n", QUAKE2_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_vmMain({} {}) returning {}\n", QUAKE2_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* QUAKE2_GetGameAPI(void* import, void*) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_GetGameAPI({}) called\n", import); +static void* QUAKE2_Entry(void* import, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_Entry({}) called\n", import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -534,7 +534,7 @@ static void* QUAKE2_GetGameAPI(void* import, void*) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = QUAKE2_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_GetGameAPI({}) returning {}\n", import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QUAKE2_Entry({}) returning {}\n", import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -543,7 +543,10 @@ static void* QUAKE2_GetGameAPI(void* import, void*) { } -static bool QUAKE2_mod_load(void* entry, bool) { +static bool QUAKE2_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); @@ -551,12 +554,12 @@ static bool QUAKE2_mod_load(void* entry, bool) { } -static void QUAKE2_mod_unload() { +static void QUAKE2_ModUnload() { orig_export = nullptr; } -static const char* QUAKE2_eng_msg_names(intptr_t cmd) { +static const char* QUAKE2_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_BPRINTF); GEN_CASE(G_DPRINTF); @@ -627,7 +630,7 @@ static const char* QUAKE2_eng_msg_names(intptr_t cmd) { } -static const char* QUAKE2_mod_msg_names(intptr_t cmd) { +static const char* QUAKE2_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAMEV_APIVERSION); GEN_CASE(GAME_INIT); diff --git a/src/game_rtcwmp.cpp b/src/game_rtcwmp.cpp index 4cfc5a3..230b3e9 100644 --- a/src/game_rtcwmp.cpp +++ b/src/game_rtcwmp.cpp @@ -20,15 +20,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(RTCWMP); -GEN_EXTS(RTCWMP); +GEN_GAME_QMM_MSGS(RTCWMP); +GEN_GAME_EXTS(RTCWMP); -GEN_DLLQVM(RTCWMP); +GEN_GAME_FUNCS_QVM(RTCWMP); // auto-detection logic for RTCWMP -static bool RTCWMP_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (is_GetGameAPI) +static bool RTCWMP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_DLLENTRY) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -54,7 +54,7 @@ static intptr_t RTCWMP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_syscall({} {}) called\n", RTCWMP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_syscall({} {}) called\n", RTCWMP_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -79,7 +79,7 @@ static intptr_t RTCWMP_syscall(intptr_t cmd, ...) { } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } @@ -87,7 +87,7 @@ static intptr_t RTCWMP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_syscall({} {}) returning {}\n", RTCWMP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_syscall({} {}) returning {}\n", RTCWMP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -100,7 +100,7 @@ static intptr_t RTCWMP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_vmMain({} {}) called\n", RTCWMP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_vmMain({} {}) called\n", RTCWMP_ModMsgNames(cmd), cmd); #endif if (!orig_vmMain) @@ -113,18 +113,18 @@ static intptr_t RTCWMP_vmMain(intptr_t cmd, ...) { ret = orig_vmMain(cmd, QMM_PUT_VMMAIN_ARGS()); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_vmMain({} {}) returning {}\n", RTCWMP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_vmMain({} {}) returning {}\n", RTCWMP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void RTCWMP_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_dllEntry({}) called\n", (void*)syscall); +static void* RTCWMP_Entry(void* syscall, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_Entry({}) called\n", syscall); // store original syscall from engine - orig_syscall = syscall; + orig_syscall = (eng_syscall)syscall; // pointer to wrapper vmMain function that calls actual mod vmMain func orig_vmMain g_gameinfo.pfnvmMain = RTCWMP_vmMain; @@ -132,23 +132,28 @@ static void RTCWMP_dllEntry(eng_syscall syscall) { // pointer to wrapper syscall function that calls actual engine syscall func g_gameinfo.pfnsyscall = RTCWMP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_dllEntry({}) returning\n", (void*)syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_Entry({}) returning\n", syscall); + + return nullptr; } -static bool RTCWMP_mod_load(void* entry, bool) { +static bool RTCWMP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_DLLENTRY && modapi != QMM_API_QVM) + return false; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } -static void RTCWMP_mod_unload() { +static void RTCWMP_ModUnload() { orig_vmMain = nullptr; } -static const char* RTCWMP_eng_msg_names(intptr_t cmd) { +static const char* RTCWMP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINT); GEN_CASE(G_ERROR); @@ -368,7 +373,7 @@ static const char* RTCWMP_eng_msg_names(intptr_t cmd) { } -static const char* RTCWMP_mod_msg_names(intptr_t cmd) { +static const char* RTCWMP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_INIT); GEN_CASE(GAME_SHUTDOWN); @@ -397,9 +402,9 @@ static const char* RTCWMP_mod_msg_names(intptr_t cmd) { */ // vec3_t are arrays, so convert them as pointers // for double pointers (gentity_t** and vec3_t*), convert them once with vmptr() -static int RTCWMP_qvmsyscall(uint8_t* membase, int cmd, int* args) { +static int RTCWMP_QVMSyscall(uint8_t* membase, int cmd, int* args) { #ifdef _DEBUG - LOG(QMM_LOG_TRACE, "QMM") << fmt::format("RTCWMP_qvmsyscall({} {}) called\n", RTCWMP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_TRACE, "QMM") << fmt::format("RTCWMP_QVMSyscall({} {}) called\n", RTCWMP_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -696,7 +701,7 @@ static int RTCWMP_qvmsyscall(uint8_t* membase, int cmd, int* args) { } #ifdef _DEBUG - LOG(QMM_LOG_TRACE, "QMM") << fmt::format("RTCWMP_qvmsyscall({} {}) returning {}\n", RTCWMP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_TRACE, "QMM") << fmt::format("RTCWMP_QVMSyscall({} {}) returning {}\n", RTCWMP_EngMsgNames(cmd), cmd, ret); #endif return ret; diff --git a/src/game_rtcwsp.cpp b/src/game_rtcwsp.cpp index 741669a..504d212 100644 --- a/src/game_rtcwsp.cpp +++ b/src/game_rtcwsp.cpp @@ -22,10 +22,10 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(RTCWSP); -GEN_EXTS(RTCWSP); +GEN_GAME_QMM_MSGS(RTCWSP); +GEN_GAME_EXTS(RTCWSP); -GEN_DLL(RTCWSP); +GEN_GAME_FUNCS(RTCWSP); #if defined(QMM_ARCH_32) && defined(QMM_OS_WINDOWS) #define MOD_DLL "x86.dll" @@ -38,13 +38,13 @@ GEN_DLL(RTCWSP); static bool is_iortcw = false; // auto-detection logic for RTCWSP -static bool RTCWSP_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (is_GetGameAPI) +static bool RTCWSP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_DLLENTRY) return false; const char* official_dllname = "qagame" MOD_DLL; - // check for iortcw name in game->dllname or official engine name + // game->dllname holds the iortcw filenames, but we also need to check for official engine dll name if (!str_striequal(g_gameinfo.qmm_file, game->dllname) && !str_striequal(g_gameinfo.qmm_file, official_dllname)) return false; @@ -58,7 +58,7 @@ static bool RTCWSP_autodetect(bool is_GetGameAPI, supportedgame* game) { game->moddir = "main"; } - // set the default dllname to whatever we loaded as to load the correct mod DLL + // set the default dllname to whatever QMM loaded as to load the correct mod DLL game->dllname = g_gameinfo.qmm_file.c_str(); return true; @@ -82,7 +82,7 @@ static intptr_t RTCWSP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_syscall({} {}) called\n", RTCWSP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_syscall({} {}) called\n", RTCWSP_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -106,9 +106,9 @@ static intptr_t RTCWSP_syscall(intptr_t cmd, ...) { break; } case G_ALLOC: { - // if we are using the iortcw game dll but not the engine, we need to handle G_ALLOC ourselves - // just malloc and store the pointer in alloc_list - // (at this time, it doesn't look like the rtcwsp game dll actually uses trap_Alloc) + // if we are using the iortcw single player game dll but not the engine, we need to handle G_ALLOC + // ourselves just malloc and store the pointer in alloc_list (although, at this time, it doesn't + // look like the iortcw single player game dll actually uses trap_Alloc) if (is_iortcw) { ret = orig_syscall(G_ALLOC, args[0]); break; @@ -119,7 +119,7 @@ static intptr_t RTCWSP_syscall(intptr_t cmd, ...) { } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } @@ -127,7 +127,7 @@ static intptr_t RTCWSP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_syscall({} {}) returning {}\n", RTCWSP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_syscall({} {}) returning {}\n", RTCWSP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -140,7 +140,7 @@ static intptr_t RTCWSP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_vmMain({} {}) called\n", RTCWSP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_vmMain({} {}) called\n", RTCWSP_ModMsgNames(cmd), cmd); #endif if (!orig_vmMain) @@ -153,18 +153,18 @@ static intptr_t RTCWSP_vmMain(intptr_t cmd, ...) { ret = orig_vmMain(cmd, QMM_PUT_VMMAIN_ARGS()); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_vmMain({} {}) returning {}\n", RTCWSP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_vmMain({} {}) returning {}\n", RTCWSP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void RTCWSP_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_dllEntry({}) called\n", (void*)syscall); +static void* RTCWSP_Entry(void* syscall, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_Entry({}) called\n", syscall); // store original syscall from engine - orig_syscall = syscall; + orig_syscall = (eng_syscall)syscall; // pointer to wrapper vmMain function that calls actual mod vmMain func orig_vmMain g_gameinfo.pfnvmMain = RTCWSP_vmMain; @@ -172,27 +172,34 @@ static void RTCWSP_dllEntry(eng_syscall syscall) { // pointer to wrapper syscall function that calls actual engine syscall func g_gameinfo.pfnsyscall = RTCWSP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_dllEntry({}) returning\n", (void*)syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_Entry({}) returning\n", syscall); + + return nullptr; } -static bool RTCWSP_mod_load(void* entry, bool) { +static bool RTCWSP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_DLLENTRY) + return false; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } -static void RTCWSP_mod_unload() { +static void RTCWSP_ModUnload() { orig_vmMain = nullptr; // free the G_ALLOC list for (void* ptr : alloc_list) free(ptr); + + alloc_list.clear(); } -static const char* RTCWSP_eng_msg_names(intptr_t cmd) { +static const char* RTCWSP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINT); GEN_CASE(G_ERROR); @@ -404,7 +411,7 @@ static const char* RTCWSP_eng_msg_names(intptr_t cmd) { } -static const char* RTCWSP_mod_msg_names(intptr_t cmd) { +static const char* RTCWSP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_INIT); GEN_CASE(GAME_SHUTDOWN); diff --git a/src/game_sin.cpp b/src/game_sin.cpp index 390950c..6a7dd6f 100644 --- a/src/game_sin.cpp +++ b/src/game_sin.cpp @@ -25,15 +25,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(SIN); -GEN_EXTS(SIN); +GEN_GAME_QMM_MSGS(SIN); +GEN_GAME_EXTS(SIN); -GEN_GGA(SIN); +GEN_GAME_FUNCS(SIN); // auto-detection logic for SIN -static bool SIN_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool SIN_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -294,7 +294,7 @@ static intptr_t SIN_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_syscall({} {}) called\n", SIN_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_syscall({} {}) called\n", SIN_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -562,7 +562,7 @@ static intptr_t SIN_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_syscall({} {}) returning {}\n", SIN_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_syscall({} {}) returning {}\n", SIN_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -575,7 +575,7 @@ static intptr_t SIN_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_vmMain({} {}) called\n", SIN_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_vmMain({} {}) called\n", SIN_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -626,15 +626,15 @@ static intptr_t SIN_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_vmMain({} {}) returning {}\n", SIN_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_vmMain({} {}) returning {}\n", SIN_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* SIN_GetGameAPI(void* import, void*) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_GetGameAPI({}) called\n", import); +static void* SIN_Entry(void* import, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_Entry({}) called\n", import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -651,7 +651,7 @@ static void* SIN_GetGameAPI(void* import, void*) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = SIN_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_GetGameAPI({}) returning {}\n", import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SIN_Entry({}) returning {}\n", import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -660,7 +660,10 @@ static void* SIN_GetGameAPI(void* import, void*) { } -static bool SIN_mod_load(void* entry, bool) { +static bool SIN_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); @@ -668,12 +671,12 @@ static bool SIN_mod_load(void* entry, bool) { } -static void SIN_mod_unload() { +static void SIN_ModUnload() { orig_export = nullptr; } -static const char* SIN_eng_msg_names(intptr_t cmd) { +static const char* SIN_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_BPRINTF); GEN_CASE(G_DPRINTF); @@ -789,7 +792,7 @@ static const char* SIN_eng_msg_names(intptr_t cmd) { } -static const char* SIN_mod_msg_names(intptr_t cmd) { +static const char* SIN_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAMEV_APIVERSION); GEN_CASE(GAME_INIT); diff --git a/src/game_sof2mp.cpp b/src/game_sof2mp.cpp index 2ace1a7..f36c114 100644 --- a/src/game_sof2mp.cpp +++ b/src/game_sof2mp.cpp @@ -22,15 +22,15 @@ Created By: #include "mod.h" #include "util.h" -GEN_QMM_MSGS(SOF2MP); -GEN_EXTS(SOF2MP); +GEN_GAME_QMM_MSGS(SOF2MP); +GEN_GAME_EXTS(SOF2MP); -GEN_DLLQVM(SOF2MP); +GEN_GAME_FUNCS_QVM(SOF2MP); // auto-detection logic for SOF2MP -static bool SOF2MP_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (is_GetGameAPI) +static bool SOF2MP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_DLLENTRY) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -56,7 +56,7 @@ static intptr_t SOF2MP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_syscall({} {}) called\n", SOF2MP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_syscall({} {}) called\n", SOF2MP_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -81,7 +81,7 @@ static intptr_t SOF2MP_syscall(intptr_t cmd, ...) { } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } @@ -90,7 +90,7 @@ static intptr_t SOF2MP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_syscall({} {}) returning {}\n", SOF2MP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_syscall({} {}) returning {}\n", SOF2MP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -103,7 +103,7 @@ static intptr_t SOF2MP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_vmMain({} {}) called\n", SOF2MP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_vmMain({} {}) called\n", SOF2MP_ModMsgNames(cmd), cmd); #endif if (!orig_vmMain) @@ -156,18 +156,18 @@ static intptr_t SOF2MP_vmMain(intptr_t cmd, ...) { } #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_vmMain({} {}) returning {}\n", SOF2MP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_vmMain({} {}) returning {}\n", SOF2MP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void SOF2MP_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_dllEntry({}) called\n", (void*)syscall); +static void* SOF2MP_Entry(void* syscall, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_Entry({}) called\n", syscall); // store original syscall from engine - orig_syscall = syscall; + orig_syscall = (eng_syscall)syscall; // pointer to wrapper vmMain function that calls actual mod vmMain func orig_vmMain g_gameinfo.pfnvmMain = SOF2MP_vmMain; @@ -175,29 +175,33 @@ static void SOF2MP_dllEntry(eng_syscall syscall) { // pointer to wrapper syscall function that calls actual engine syscall func g_gameinfo.pfnsyscall = SOF2MP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_dllEntry({}) returning\n", (void*)syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_Entry({}) returning\n", syscall); + + return nullptr; } // get mod's vmMain function pointer from mod.cpp::mod_load -static bool SOF2MP_mod_load(void* entry, bool) { +static bool SOF2MP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_DLLENTRY && modapi != QMM_API_QVM) + return false; + orig_vmMain = (mod_vmMain)entry; // we cannot verify data in the QVM since this engine both provides malloc functionality and has the gametype module, // so some pointers may point into the engine or the gametype module - if (g_mod.vmbase) - g_mod.vm.verify_data = false; + g_mod.vm.verify_data = false; return !!orig_vmMain; } -static void SOF2MP_mod_unload() { +static void SOF2MP_ModUnload() { orig_vmMain = nullptr; } -static const char* SOF2MP_eng_msg_names(intptr_t cmd) { +static const char* SOF2MP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINT); GEN_CASE(G_ERROR); @@ -470,7 +474,7 @@ static const char* SOF2MP_eng_msg_names(intptr_t cmd) { } -static const char* SOF2MP_mod_msg_names(intptr_t cmd) { +static const char* SOF2MP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_INIT); GEN_CASE(GAME_SHUTDOWN); @@ -502,9 +506,9 @@ static const char* SOF2MP_mod_msg_names(intptr_t cmd) { // do NOT convert the "ghoul" void pointers, treat them as plain ints // TGPValue, TGPGroup, and TGenericParser2 are void*, but treat them as plain ints // for double pointers (gentity_t**, vec3_t*, void**), convert them once with vmptr() -static int SOF2MP_qvmsyscall(uint8_t* membase, int cmd, int* args) { +static int SOF2MP_QVMSyscall(uint8_t* membase, int cmd, int* args) { #ifdef _DEBUG - LOG(QMM_LOG_TRACE, "QMM") << fmt::format("SOF2MP_qvmsyscall({} {}) called\n", SOF2MP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_TRACE, "QMM") << fmt::format("SOF2MP_QVMSyscall({} {}) called\n", SOF2MP_EngMsgNames(cmd), cmd); #endif int ret = 0; @@ -876,7 +880,7 @@ static int SOF2MP_qvmsyscall(uint8_t* membase, int cmd, int* args) { } #ifdef _DEBUG - LOG(QMM_LOG_TRACE, "QMM") << fmt::format("SOF2MP_qvmsyscall({} {}) returning {}\n", SOF2MP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_TRACE, "QMM") << fmt::format("SOF2MP_QVMSyscall({} {}) returning {}\n", SOF2MP_EngMsgNames(cmd), cmd, ret); #endif return ret; diff --git a/src/game_sof2sp.cpp b/src/game_sof2sp.cpp index 8bee164..908f75e 100644 --- a/src/game_sof2sp.cpp +++ b/src/game_sof2sp.cpp @@ -18,15 +18,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(SOF2SP); -GEN_EXTS(SOF2SP); +GEN_GAME_QMM_MSGS(SOF2SP); +GEN_GAME_EXTS(SOF2SP); -GEN_GGA(SOF2SP); +GEN_GAME_FUNCS(SOF2SP); // auto-detection logic for SOF2SP -static bool SOF2SP_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool SOF2SP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -214,7 +214,7 @@ static intptr_t SOF2SP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_syscall({} {}) called\n", SOF2SP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_syscall({} {}) called\n", SOF2SP_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -376,7 +376,7 @@ static intptr_t SOF2SP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_syscall({} {}) returning {}\n", SOF2SP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_syscall({} {}) returning {}\n", SOF2SP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -389,7 +389,7 @@ static intptr_t SOF2SP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_vmMain({} {}) called\n", SOF2SP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_vmMain({} {}) called\n", SOF2SP_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -435,16 +435,16 @@ static intptr_t SOF2SP_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_vmMain({} {}) returning {}\n", SOF2SP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_vmMain({} {}) returning {}\n", SOF2SP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* SOF2SP_GetGameAPI(void* apiversion, void* import) { +static void* SOF2SP_Entry(void* apiversion, void* import, APIType) { orig_apiversion = (intptr_t)apiversion; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_GetGameAPI({}, {}) called\n", orig_apiversion, import); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_Entry({}, {}) called\n", orig_apiversion, import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -460,7 +460,7 @@ static void* SOF2SP_GetGameAPI(void* apiversion, void* import) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = SOF2SP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_GetGameAPI({}, {}) returning {}\n", orig_apiversion, import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2SP_Entry({}, {}) returning {}\n", orig_apiversion, import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -469,7 +469,10 @@ static void* SOF2SP_GetGameAPI(void* apiversion, void* import) { } -static bool SOF2SP_mod_load(void* entry, bool) { +static bool SOF2SP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; // api version gets passed before import pointer orig_export = (game_export_t*)pfnGGA((void*)orig_apiversion, &qmm_import); @@ -478,12 +481,12 @@ static bool SOF2SP_mod_load(void* entry, bool) { } -static void SOF2SP_mod_unload() { +static void SOF2SP_ModUnload() { orig_export = nullptr; } -static const char* SOF2SP_eng_msg_names(intptr_t cmd) { +static const char* SOF2SP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_DPRINTF); @@ -608,7 +611,7 @@ static const char* SOF2SP_eng_msg_names(intptr_t cmd) { } -static const char* SOF2SP_mod_msg_names(intptr_t cmd) { +static const char* SOF2SP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_INIT); GEN_CASE(GAME_SHUTDOWN); diff --git a/src/game_stef2.cpp b/src/game_stef2.cpp index c07061a..2c72628 100644 --- a/src/game_stef2.cpp +++ b/src/game_stef2.cpp @@ -23,15 +23,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(STEF2); -GEN_EXTS(STEF2); +GEN_GAME_QMM_MSGS(STEF2); +GEN_GAME_EXTS(STEF2); -GEN_GGA(STEF2); +GEN_GAME_FUNCS(STEF2); // auto-detection logic for STEF2 -static bool STEF2_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool STEF2_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -491,7 +491,7 @@ static intptr_t STEF2_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_syscall({} {}) called\n", STEF2_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_syscall({} {}) called\n", STEF2_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -882,7 +882,7 @@ static intptr_t STEF2_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_syscall({} {}) returning {}\n", STEF2_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_syscall({} {}) returning {}\n", STEF2_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -895,7 +895,7 @@ static intptr_t STEF2_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_vmMain({} {}) called\n", STEF2_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_vmMain({} {}) called\n", STEF2_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -953,15 +953,15 @@ static intptr_t STEF2_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_vmMain({} {}) returning {}\n", STEF2_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_vmMain({} {}) returning {}\n", STEF2_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* STEF2_GetGameAPI(void* import, void*) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_GetGameAPI({}) called\n", import); +static void* STEF2_Entry(void* import, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_Entry({}) called\n", import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -978,7 +978,7 @@ static void* STEF2_GetGameAPI(void* import, void*) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = STEF2_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_GetGameAPI({}) returning {}\n", import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STEF2_Entry({}) returning {}\n", import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -987,7 +987,10 @@ static void* STEF2_GetGameAPI(void* import, void*) { } -static bool STEF2_mod_load(void* entry, bool) { +static bool STEF2_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); @@ -995,12 +998,12 @@ static bool STEF2_mod_load(void* entry, bool) { } -static void STEF2_mod_unload() { +static void STEF2_ModUnload() { orig_export = nullptr; } -static const char* STEF2_eng_msg_names(intptr_t cmd) { +static const char* STEF2_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_DPRINTF); @@ -1353,7 +1356,7 @@ static const char* STEF2_eng_msg_names(intptr_t cmd) { } -static const char* STEF2_mod_msg_names(intptr_t cmd) { +static const char* STEF2_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAMEV_APIVERSION); GEN_CASE(GAME_INIT); diff --git a/src/game_stvoyhm.cpp b/src/game_stvoyhm.cpp index 3b23d65..da617d4 100644 --- a/src/game_stvoyhm.cpp +++ b/src/game_stvoyhm.cpp @@ -21,15 +21,15 @@ Created By: #include "mod.h" #include "util.h" -GEN_QMM_MSGS(STVOYHM); -GEN_EXTS(STVOYHM); +GEN_GAME_QMM_MSGS(STVOYHM); +GEN_GAME_EXTS(STVOYHM); -GEN_DLLQVM(STVOYHM); +GEN_GAME_FUNCS_QVM(STVOYHM); // auto-detection logic for Q3A -static bool STVOYHM_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (is_GetGameAPI) +static bool STVOYHM_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_DLLENTRY) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -55,7 +55,7 @@ static intptr_t STVOYHM_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_syscall({} {}) called\n", STVOYHM_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_syscall({} {}) called\n", STVOYHM_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -80,7 +80,7 @@ static intptr_t STVOYHM_syscall(intptr_t cmd, ...) { } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } @@ -88,7 +88,7 @@ static intptr_t STVOYHM_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_syscall({} {}) returning {}\n", STVOYHM_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_syscall({} {}) returning {}\n", STVOYHM_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -101,7 +101,7 @@ static intptr_t STVOYHM_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_vmMain({} {}) called\n", STVOYHM_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_vmMain({} {}) called\n", STVOYHM_ModMsgNames(cmd), cmd); #endif if (!orig_vmMain) @@ -120,18 +120,18 @@ static intptr_t STVOYHM_vmMain(intptr_t cmd, ...) { } #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_vmMain({} {}) returning {}\n", STVOYHM_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_vmMain({} {}) returning {}\n", STVOYHM_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void STVOYHM_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_dllEntry({}) called\n", (void*)syscall); +static void* STVOYHM_Entry(void* syscall, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_Entry({}) called\n", syscall); // store original syscall from engine - orig_syscall = syscall; + orig_syscall = (eng_syscall)syscall; // pointer to wrapper vmMain function that calls actual mod vmMain func orig_vmMain g_gameinfo.pfnvmMain = STVOYHM_vmMain; @@ -139,23 +139,28 @@ static void STVOYHM_dllEntry(eng_syscall syscall) { // pointer to wrapper syscall function that calls actual engine syscall func g_gameinfo.pfnsyscall = STVOYHM_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_dllEntry({}) returning\n", (void*)syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_Entry({}) returning\n", syscall); + + return nullptr; } -static bool STVOYHM_mod_load(void* entry, bool) { +static bool STVOYHM_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_DLLENTRY && modapi != QMM_API_QVM) + return false; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } -static void STVOYHM_mod_unload() { +static void STVOYHM_ModUnload() { orig_vmMain = nullptr; } -static const char* STVOYHM_eng_msg_names(intptr_t cmd) { +static const char* STVOYHM_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINT); GEN_CASE(G_ERROR); @@ -355,7 +360,7 @@ static const char* STVOYHM_eng_msg_names(intptr_t cmd) { } -static const char* STVOYHM_mod_msg_names(intptr_t cmd) { +static const char* STVOYHM_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_INIT); GEN_CASE(GAME_SHUTDOWN); @@ -381,9 +386,9 @@ static const char* STVOYHM_mod_msg_names(intptr_t cmd) { */ // vec3_t are arrays, so convert them as pointers // for double pointers (gentity_t** and vec3_t*), convert them once with vmptr() -static int STVOYHM_qvmsyscall(uint8_t* membase, int cmd, int* args) { +static int STVOYHM_QVMSyscall(uint8_t* membase, int cmd, int* args) { #ifdef _DEBUG - LOG(QMM_LOG_TRACE, "QMM") << fmt::format("STVOYHM_qvmsyscall({} {}) called\n", STVOYHM_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_TRACE, "QMM") << fmt::format("STVOYHM_QVMSyscall({} {}) called\n", STVOYHM_EngMsgNames(cmd), cmd); #endif int ret = 0; @@ -648,7 +653,7 @@ static int STVOYHM_qvmsyscall(uint8_t* membase, int cmd, int* args) { } #ifdef _DEBUG - LOG(QMM_LOG_TRACE, "QMM") << fmt::format("STVOYHM_qvmsyscall({} {}) returning {}\n", STVOYHM_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_TRACE, "QMM") << fmt::format("STVOYHM_QVMSyscall({} {}) returning {}\n", STVOYHM_EngMsgNames(cmd), cmd, ret); #endif return ret; diff --git a/src/game_stvoysp.cpp b/src/game_stvoysp.cpp index 41da018..96ea858 100644 --- a/src/game_stvoysp.cpp +++ b/src/game_stvoysp.cpp @@ -21,15 +21,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(STVOYSP); -GEN_EXTS(STVOYSP); +GEN_GAME_QMM_MSGS(STVOYSP); +GEN_GAME_EXTS(STVOYSP); -GEN_GGA(STVOYSP); +GEN_GAME_FUNCS(STVOYSP); // auto-detection logic for STVOYSP -static bool STVOYSP_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (!is_GetGameAPI) +static bool STVOYSP_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_GETGAMEAPI) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -169,7 +169,7 @@ static intptr_t STVOYSP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_syscall({} {}) called\n", STVOYSP_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_syscall({} {}) called\n", STVOYSP_EngMsgNames(cmd), cmd); #endif // update export vars before calling into the engine @@ -290,7 +290,7 @@ static intptr_t STVOYSP_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_syscall({} {}) returning {}\n", STVOYSP_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_syscall({} {}) returning {}\n", STVOYSP_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -303,7 +303,7 @@ static intptr_t STVOYSP_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_vmMain({} {}) called\n", STVOYSP_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_vmMain({} {}) called\n", STVOYSP_ModMsgNames(cmd), cmd); #endif if (!orig_export) @@ -341,15 +341,15 @@ static intptr_t STVOYSP_vmMain(intptr_t cmd, ...) { s_update_export(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_vmMain({} {}) returning {}\n", STVOYSP_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_vmMain({} {}) returning {}\n", STVOYSP_ModMsgNames(cmd), cmd, ret); #endif return ret; } -static void* STVOYSP_GetGameAPI(void* import, void*) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_GetGameAPI({}) called\n", import); +static void* STVOYSP_Entry(void* import, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_Entry({}) called\n", import); // original import struct from engine // the struct given by the engine goes out of scope after this returns so we have to copy the whole thing @@ -365,7 +365,7 @@ static void* STVOYSP_GetGameAPI(void* import, void*) { // pointer to wrapper syscall function that calls actual engine func from orig_import g_gameinfo.pfnsyscall = STVOYSP_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_GetGameAPI({}) returning {}\n", import, (void*)&qmm_export); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYSP_Entry({}) returning {}\n", import, (void*)&qmm_export); // struct full of export lambdas to QMM's vmMain // this gets returned to the game engine, but we haven't loaded the mod yet. @@ -374,7 +374,10 @@ static void* STVOYSP_GetGameAPI(void* import, void*) { } -static bool STVOYSP_mod_load(void* entry, bool) { +static bool STVOYSP_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_GETGAMEAPI) + return false; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); @@ -382,12 +385,12 @@ static bool STVOYSP_mod_load(void* entry, bool) { } -static void STVOYSP_mod_unload() { +static void STVOYSP_ModUnload() { orig_export = nullptr; } -static const char* STVOYSP_eng_msg_names(intptr_t cmd) { +static const char* STVOYSP_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINTF); GEN_CASE(G_WRITECAM); @@ -444,7 +447,7 @@ static const char* STVOYSP_eng_msg_names(intptr_t cmd) { } -static const char* STVOYSP_mod_msg_names(intptr_t cmd) { +static const char* STVOYSP_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAMEV_APIVERSION); GEN_CASE(GAME_INIT); diff --git a/src/game_wet.cpp b/src/game_wet.cpp index d35c980..cd5c0ee 100644 --- a/src/game_wet.cpp +++ b/src/game_wet.cpp @@ -20,15 +20,15 @@ Created By: #include "main.h" #include "util.h" -GEN_QMM_MSGS(WET); -GEN_EXTS(WET); +GEN_GAME_QMM_MSGS(WET); +GEN_GAME_EXTS(WET); -GEN_DLL(WET); +GEN_GAME_FUNCS(WET); // auto-detection logic for WET -static bool WET_autodetect(bool is_GetGameAPI, supportedgame* game) { - if (is_GetGameAPI) +static bool WET_AutoDetect(api_supportedgame* game, APIType engineapi) { + if (engineapi != QMM_API_DLLENTRY) return false; if (!str_striequal(g_gameinfo.qmm_file, game->dllname)) @@ -49,12 +49,12 @@ static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func in orig_syscall // this is how QMM and plugins will call into the engine -intptr_t WET_syscall(intptr_t cmd, ...) { +static intptr_t WET_syscall(intptr_t cmd, ...) { QMM_GET_SYSCALL_ARGS(); #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_syscall({} {}) called\n", WET_eng_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_syscall({} {}) called\n", WET_EngMsgNames(cmd), cmd); #endif intptr_t ret = 0; @@ -79,7 +79,7 @@ intptr_t WET_syscall(intptr_t cmd, ...) { } default: - // all normal engine functions go to engine + // all normal engine functions go to syscall ret = orig_syscall(cmd, QMM_PUT_SYSCALL_ARGS()); } @@ -87,7 +87,7 @@ intptr_t WET_syscall(intptr_t cmd, ...) { #ifdef _DEBUG if (cmd != G_PRINT) - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_syscall({} {}) returning {}\n", WET_eng_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_syscall({} {}) returning {}\n", WET_EngMsgNames(cmd), cmd, ret); #endif return ret; @@ -96,11 +96,11 @@ intptr_t WET_syscall(intptr_t cmd, ...) { // wrapper vmMain function that calls actual mod func in orig_vmMain // this is how QMM and plugins will call into the mod -intptr_t WET_vmMain(intptr_t cmd, ...) { +static intptr_t WET_vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_vmMain({} {}) called\n", WET_mod_msg_names(cmd), cmd); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_vmMain({} {}) called\n", WET_ModMsgNames(cmd), cmd); #endif if (!orig_vmMain) @@ -113,18 +113,18 @@ intptr_t WET_vmMain(intptr_t cmd, ...) { ret = orig_vmMain(cmd, QMM_PUT_VMMAIN_ARGS()); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_vmMain({} {}) returning {}\n", WET_mod_msg_names(cmd), cmd, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_vmMain({} {}) returning {}\n", WET_ModMsgNames(cmd), cmd, ret); #endif return ret; } -void WET_dllEntry(eng_syscall syscall) { - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_dllEntry({}) called\n", (void*)syscall); +static void* WET_Entry(void* syscall, void*, APIType) { + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_Entry({}) called\n", syscall); // store original syscall from engine - orig_syscall = syscall; + orig_syscall = (eng_syscall)syscall; // pointer to wrapper vmMain function that calls actual mod vmMain func orig_vmMain g_gameinfo.pfnvmMain = WET_vmMain; @@ -132,23 +132,28 @@ void WET_dllEntry(eng_syscall syscall) { // pointer to wrapper syscall function that calls actual engine syscall func g_gameinfo.pfnsyscall = WET_syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_dllEntry({}) returning\n", (void*)syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_Entry({}) returning\n", syscall); + + return nullptr; } -bool WET_mod_load(void* entry, bool) { +static bool WET_ModLoad(void* entry, APIType modapi) { + if (modapi != QMM_API_DLLENTRY) + return false; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } -void WET_mod_unload() { +static void WET_ModUnload() { orig_vmMain = nullptr; } -const char* WET_eng_msg_names(intptr_t cmd) { +static const char* WET_EngMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(G_PRINT); GEN_CASE(G_ERROR); @@ -379,7 +384,7 @@ const char* WET_eng_msg_names(intptr_t cmd) { } -const char* WET_mod_msg_names(intptr_t cmd) { +static const char* WET_ModMsgNames(intptr_t cmd) { switch (cmd) { GEN_CASE(GAME_INIT); GEN_CASE(GAME_SHUTDOWN); diff --git a/src/main.cpp b/src/main.cpp index 1b85a6d..a7b3a7c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,13 +27,13 @@ Created By: gameinfo g_gameinfo; // shared code for dllEntry and GetGameAPI entry points -static void* main_handle_entry(void* import, void* extra, bool is_GetGameAPI); +static void* main_handle_entry(void* import, void* extra, APIType engine); // general code to get path/module/binary/etc information static void main_detect_env(); // general code to load config file static void main_load_config(std::string config_filename); // general code to auto-detect what game engine loaded us -static void main_detect_game(std::string cfg_game, bool is_GetGameAPI); +static void main_detect_game(std::string cfg_game, APIType engine); // general code to find a mod file to load static bool main_load_mod(std::string cfg_mod); // general code to find a plugin file to load @@ -65,7 +65,7 @@ static intptr_t main_route(bool is_syscall, intptr_t cmd, intptr_t* args); is returned to engine syscall (mod->engine) call flow for QVM mods only: - 1. QVM system calls _qvmsyscall function + 1. QVM system calls _QVMSyscall function 2. pointer arguments are converted: if not NULL, the QVM data segment base address is added 3. call qmm_syscall with converted arguments (continue with next section as if it were a DLL mod) @@ -134,7 +134,11 @@ C_DLLEXPORT void dllEntry(void* syscall) { return; } - main_handle_entry(syscall, nullptr, false); // false = !is_GetGameAPI + // store the given syscall pointer as a backup (should get overwritten in game-specific entry handler), and so + // if we don't detect a game, we can call syscall(G_ERROR) to shutdown in vmMain + g_gameinfo.pfnsyscall = (eng_syscall)syscall; + + main_handle_entry(syscall, nullptr, QMM_API_DLLENTRY); return; } @@ -188,15 +192,17 @@ C_DLLEXPORT void dllEntry(void* syscall) { The original import/export tables are stored. When QMM and plugins need to call the mod or engine, g_gameinfo.pfnvmMain or g_gameinfo.pfnsyscall point to game-specific functions which will take the cmd, and route to the proper function pointer in the struct. + + SOF2SP engine passes an apiversion as the first arg, and import is the second arg */ C_DLLEXPORT void* GetGameAPI(void* import, void* extra) { - return main_handle_entry(import, extra, true); // true = is_GetGameAPI + return main_handle_entry(import, extra, QMM_API_GETGAMEAPI); } // this is the same as the 2-arg GetGameAPI but OpenJK renamed it C_DLLEXPORT void* GetModuleAPI(void* import, void* extra) { - return main_handle_entry(import, extra, true); // true = is_GetGameAPI + return main_handle_entry(import, extra, QMM_API_GETMODULEAPI); } @@ -301,10 +307,10 @@ C_DLLEXPORT intptr_t vmMain(intptr_t cmd, ...) { ENG_SYSCALL(QMM_FAIL_G_ERROR, "\nFatal QMM Error:\nQMM was unable to load the mod file.\nPlease set the \"mod\" option in qmm2.json.\nRefer to the documentation for more information.\n"); return 0; } - LOG(QMM_LOG_NOTICE, "QMM") << fmt::format("Successfully loaded {} mod \"{}\"\n", g_mod.vmbase ? "VM" : "DLL", g_mod.path); + LOG(QMM_LOG_NOTICE, "QMM") << fmt::format("Successfully loaded {} mod \"{}\"\n", APIType_Function(g_mod.api), g_mod.path); // cgame passthrough hack: - // mod DLL is loaded, so find the vmMain and dllEntry functions and call dllEntry + // mod DLL is loaded, so find the vmMain and dllEntry functions and call dllEntry. // JASP+JK2SP's cgame dllEntry functions actually call into the syscall almost immediately, // so make sure we store vmMain first in case there's some re-entrancy if (cgame.syscall) { @@ -380,7 +386,7 @@ C_DLLEXPORT intptr_t vmMain(intptr_t cmd, ...) { // unload each plugin (call QMM_Detach, and then dlclose) LOG(QMM_LOG_NOTICE, "QMM") << "Shutting down plugins\n"; - for (plugin& p : g_plugins) { + for (qmm_plugin& p : g_plugins) { plugin_unload(p); } g_plugins.clear(); @@ -419,22 +425,23 @@ intptr_t qmm_syscall(intptr_t cmd, ...) { } -static void* main_handle_entry(void* import, void* extra, bool is_GetGameAPI) { - const char* func_name = is_GetGameAPI ? "GetGameAPI" : "dllEntry"; - +static void* main_handle_entry(void* import, void* extra, APIType engine) { main_detect_env(); + g_gameinfo.api = engine; + log_init(fmt::format("{}/qmm2.log", g_gameinfo.qmm_dir)); - LOG(QMM_LOG_NOTICE, "QMM") << fmt::format("QMM v" QMM_VERSION " (" QMM_OS " " QMM_ARCH ") ({}) loaded!\n", func_name); + LOG(QMM_LOG_NOTICE, "QMM") << fmt::format("QMM v" QMM_VERSION " (" QMM_OS " " QMM_ARCH ") ({}) loaded!\n", APIType_Function(engine)); LOG(QMM_LOG_INFO, "QMM") << fmt::format("QMM path: \"{}\"\n", g_gameinfo.qmm_path); LOG(QMM_LOG_INFO, "QMM") << fmt::format("Engine path: \"{}\"\n", g_gameinfo.exe_path); LOG(QMM_LOG_INFO, "QMM") << fmt::format("Mod directory (?): \"{}\"\n", g_gameinfo.mod_dir); // ??? // return nullptr to error out now. if GetGameAPI, Init() will never be called + // if dllEntry, will check g_gameinfo.game in vmMain(GAME_INIT) and call G_ERROR if (!import) { - LOG(QMM_LOG_FATAL, "QMM") << fmt::format("{}(): {} is NULL!\n", func_name, is_GetGameAPI ? "import" : "syscall"); + LOG(QMM_LOG_FATAL, "QMM") << fmt::format("{}(): engine pointer is NULL!\n", APIType_Function(engine)); return nullptr; } @@ -450,15 +457,24 @@ static void* main_handle_entry(void* import, void* extra, bool is_GetGameAPI) { std::string cfg_game = cfg_get_string(g_cfg, "game", "auto"); // check command line arguments for a game code cfg_game = util_get_cmdline_arg("--qmm_game", cfg_game); - main_detect_game(cfg_game, is_GetGameAPI); + main_detect_game(cfg_game, engine); // failed to get engine information - // return nullptr to error out now. if GetGameAPI, Init() will never be called + // if GetGameAPI, returning nullptr to error out now will make sure Init() will never be called. + // if dllEntry, will check g_gameinfo.game in vmMain(GAME_INIT) and call G_ERROR if (!g_gameinfo.game) { - LOG(QMM_LOG_FATAL, "QMM") << fmt::format("{}(): Unable to determine game engine using \"{}\"\n", func_name, cfg_game); - // if dllEntry, store the given syscall pointer so we can call G_ERROR to shutdown in vmMain - if (!is_GetGameAPI) - g_gameinfo.pfnsyscall = (eng_syscall)import; + LOG(QMM_LOG_FATAL, "QMM") << fmt::format("{}(): Unable to determine game engine using \"{}\"\n", APIType_Function(engine), cfg_game); + return nullptr; + } + + // game support must have an entry function and message arrays+functions + if (!g_gameinfo.game->funcs->pfnEntry + || !g_gameinfo.game->funcs->qmm_eng_msgs + || !g_gameinfo.game->funcs->qmm_mod_msgs + || !g_gameinfo.game->funcs->pfnEngMsgNames + || !g_gameinfo.game->funcs->pfnModMsgNames) + { + LOG(QMM_LOG_FATAL, "QMM") << fmt::format("{}(): Missing required function(s) for game \"{}\"\n", APIType_Function(engine), g_gameinfo.game->gamename_short); return nullptr; } @@ -468,30 +484,9 @@ static void* main_handle_entry(void* import, void* extra, bool is_GetGameAPI) { msg_GAME_CONSOLE_COMMAND = QMM_MOD_MSG[QMM_GAME_CONSOLE_COMMAND]; msg_GAME_SHUTDOWN = QMM_MOD_MSG[QMM_GAME_SHUTDOWN]; - if (is_GetGameAPI) { - // supported games table is missing game-specific GetGameAPI handler? - // return nullptr to error out now. Init() will never be called - if (!g_gameinfo.game->funcs->pfnGetGameAPI) { - LOG(QMM_LOG_FATAL, "QMM") << fmt::format("GetGameAPI(): pfnGetGameAPI handler for game \"{}\" is NULL!\n", g_gameinfo.game->gamename_short); - return nullptr; - } - - // call the game-specific GetGameAPI function (e.g. MOHAA_GetGameAPI) which will set up the exports for - // returning here back to the game engine, as well as save the imports in preparation of loading the mod - return g_gameinfo.game->funcs->pfnGetGameAPI(import, extra); - } - - // call the game-specific dllEntry function (e.g. Q3A_dllEntry) which will set up the functions to handle - // vmMain and syscalls from the mod, engine, and plugins - if (g_gameinfo.game->funcs->pfndllEntry) - g_gameinfo.game->funcs->pfndllEntry((eng_syscall)import); - // supported games table is missing game-specific dllEntry handler? we can try to fake it by storing the - // syscall pointer in g_gameinfo.pfnsyscall. also as a hack, s_mod_load_vmmain & s_mod_load_qvm will store - // vmMain in g_gameinfo.pfnvmMain if it wasn't set already by the game-specific dllEntry - else - g_gameinfo.pfnsyscall = (eng_syscall)import; - - return nullptr; + // call the game-specific entry handler (e.g. Q3A_Entry) which will set up the internals to interact + // the engine and the mod + return g_gameinfo.game->funcs->pfnEntry(import, extra, engine); } @@ -555,8 +550,8 @@ static void main_load_config(std::string config_filename) { // general code to auto-detect what game engine loaded us -static void main_detect_game(std::string cfg_game, bool is_GetGameAPI) { - for (supportedgame& game : g_supportedgames) { +static void main_detect_game(std::string cfg_game, APIType engine) { + for (api_supportedgame& game : api_supportedgames) { // if short name matches config option, we found it! if (str_striequal(cfg_game, game.gamename_short)) { LOG(QMM_LOG_NOTICE, "QMM") << fmt::format("Found game match for config option \"{}\"\n", cfg_game); @@ -564,12 +559,15 @@ static void main_detect_game(std::string cfg_game, bool is_GetGameAPI) { g_gameinfo.is_auto_detected = false; // call the game's auto-detect function if it exists, since it may do some logic if (game.funcs->pfnAutoDetect) - (void)game.funcs->pfnAutoDetect(is_GetGameAPI, &game); + (void)game.funcs->pfnAutoDetect(&game, engine); return; } // otherwise, if auto, call the game's auto-detect function if available - if (str_striequal(cfg_game, "auto") && game.funcs->pfnAutoDetect && game.funcs->pfnAutoDetect(is_GetGameAPI, &game)) { + if (str_striequal(cfg_game, "auto") + && game.funcs->pfnAutoDetect + && game.funcs->pfnAutoDetect(&game, engine)) + { LOG(QMM_LOG_INFO, "QMM") << fmt::format("Found game match with auto-detection - \"{}\"\n", game.gamename_short); g_gameinfo.game = &game; g_gameinfo.is_auto_detected = true; @@ -633,7 +631,7 @@ static bool main_load_mod(std::string cfg_mod) { // general code to find a plugin file to load static bool main_load_plugin(std::string plugin_path) { - plugin p; + qmm_plugin p; // absolute path, just attempt to load it directly if (!path_is_relative(plugin_path)) { // plugin_load returns 0 if no plugin file was found, 1 if success, and -1 if file was found but failure @@ -678,14 +676,14 @@ static void main_handle_command_qmm(intptr_t arg_start) { if (str_striequal("status", arg1) || str_striequal("info", arg1)) { CONSOLE_PRINT("(QMM) QMM v" QMM_VERSION " (" QMM_OS " " QMM_ARCH ")\n"); - CONSOLE_PRINTF("(QMM) Game: {}/\"{}\" (Source: {})\n", g_gameinfo.game->gamename_short, g_gameinfo.game->gamename_long, g_gameinfo.is_auto_detected ? "Auto-detected" : "Config file"); + CONSOLE_PRINTF("(QMM) Game: {}/\"{}\" ({}) (Source: {})\n", g_gameinfo.game->gamename_short, g_gameinfo.game->gamename_long, APIType_Function(g_gameinfo.api), g_gameinfo.is_auto_detected ? "Auto-detected" : "Config file"); CONSOLE_PRINTF("(QMM) ModDir: {}\n", g_gameinfo.mod_dir); - CONSOLE_PRINTF("(QMM) Config file: \"{}\" {}\n", g_gameinfo.cfg_path, g_cfg.is_discarded() ? " (error)" : ""); + CONSOLE_PRINTF("(QMM) Config file: \"{}\" {}\n", g_gameinfo.cfg_path, g_cfg.empty() ? "(error)" : ""); CONSOLE_PRINT("(QMM) Built: " QMM_COMPILE " by " QMM_BUILDER "\n"); CONSOLE_PRINT("(QMM) URL: " QMM_URL "\n"); CONSOLE_PRINT("(QMM) Plugin interface: " STRINGIFY(QMM_PIFV_MAJOR) ":" STRINGIFY(QMM_PIFV_MINOR) "\n"); CONSOLE_PRINTF("(QMM) Plugins loaded: {}\n", g_plugins.size()); - CONSOLE_PRINTF("(QMM) Loaded mod file: {}\n", g_mod.path); + CONSOLE_PRINTF("(QMM) Loaded mod: {} ({})\n", g_mod.path, APIType_Function(g_mod.api)); if (g_mod.vmbase) { CONSOLE_PRINTF("(QMM) QVM magic number : {:x} ({})\n", g_mod.vm.magic, g_mod.vm.magic == QVM_MAGIC ? "QVM_MAGIC" : "QVM_MAGIC_VER2"); CONSOLE_PRINTF("(QMM) QVM file size : {}\n", g_mod.vm.filesize); @@ -702,7 +700,7 @@ static void main_handle_command_qmm(intptr_t arg_start) { CONSOLE_PRINT("(QMM) id - plugin [version]\n"); CONSOLE_PRINT("(QMM) ---------------------\n"); int num = 1; - for (plugin& p : g_plugins) { + for (qmm_plugin& p : g_plugins) { CONSOLE_PRINTF("(QMM) {:>2} - {} [{}]\n", num, p.plugininfo->name, p.plugininfo->version); num++; } @@ -714,7 +712,7 @@ static void main_handle_command_qmm(intptr_t arg_start) { } size_t pid = (size_t)atoi(arg2); if (pid > 0 && pid <= g_plugins.size()) { - plugin& p = g_plugins[pid - 1]; + qmm_plugin& p = g_plugins[pid - 1]; CONSOLE_PRINTF("(QMM) Plugin info for #{}:\n", arg2); CONSOLE_PRINTF("(QMM) Name: {}\n", p.plugininfo->name); CONSOLE_PRINTF("(QMM) Version: {}\n", p.plugininfo->version); @@ -738,6 +736,10 @@ static void main_handle_command_qmm(intptr_t arg_start) { log_set_severity(severity); CONSOLE_PRINTF("(QMM) Log level set to {}\n", log_name_from_severity(severity)); } + else if (str_striequal("reload", arg1)) { + g_cfg = cfg_load(g_gameinfo.cfg_path); + CONSOLE_PRINT("(QMM) Configuration file reloaded!\n"); + } else { CONSOLE_PRINT("(QMM) Usage: qmm [params]\n"); CONSOLE_PRINT("(QMM) Available commands:\n"); @@ -745,6 +747,7 @@ static void main_handle_command_qmm(intptr_t arg_start) { CONSOLE_PRINT("(QMM) qmm list - displays information about loaded QMM plugins\n"); CONSOLE_PRINT("(QMM) qmm plugin - outputs info on plugin with id\n"); CONSOLE_PRINT("(QMM) qmm loglevel - changes QMM log level: TRACE, DEBUG, INFO, NOTICE, WARNING, ERROR, FATAL\n"); + CONSOLE_PRINT("(QMM) qmm reload - reloads the QMM configuration file\n"); } } @@ -777,7 +780,7 @@ static intptr_t main_route(bool is_syscall, intptr_t cmd, intptr_t* args) { intptr_t final_ret = 0; // begin passing calls to plugins' pre-hook functions - for (plugin& p : g_plugins) { + for (qmm_plugin& p : g_plugins) { g_plugin_globals.plugin_result = QMM_UNUSED; // allow plugins to see the current final_ret value g_plugin_globals.final_return = final_ret; @@ -839,7 +842,7 @@ static intptr_t main_route(bool is_syscall, intptr_t cmd, intptr_t* args) { final_ret = real_ret; // pass calls to plugins' post-hook functions (QMM_OVERRIDE or QMM_SUPERCEDE can still change final_ret) - for (plugin& p : g_plugins) { + for (qmm_plugin& p : g_plugins) { g_plugin_globals.plugin_result = QMM_UNUSED; // allow plugins to see the current final_ret value g_plugin_globals.final_return = final_ret; diff --git a/src/mod.cpp b/src/mod.cpp index bf8dda8..4b0d2e0 100644 --- a/src/mod.cpp +++ b/src/mod.cpp @@ -23,14 +23,15 @@ Created By: #include "plugin.h" #include "util.h" -mod g_mod; +qmm_mod g_mod; static intptr_t s_mod_qvm_vmmain(intptr_t cmd, ...); static int s_mod_qvm_syscall(uint8_t* membase, int cmd, int* args); -static bool s_mod_load_qvm(mod& mod); +static bool s_mod_load_qvm(qmm_mod& mod); +static bool s_mod_load_dll(qmm_mod& mod, APIType api); -bool mod_load(mod& mod, std::string file) { +bool mod_load(qmm_mod& mod, std::string file) { // if this mod somehow already has a dll or qvm pointer, wipe it first if (mod.dll || mod.vm.memory) mod_unload(mod); @@ -40,93 +41,56 @@ bool mod_load(mod& mod, std::string file) { std::string ext = path_baseext(file); // only allow qvm mods if the game engine supports it - if (str_striequal(ext, EXT_QVM) && g_gameinfo.game->funcs->pfnqvmsyscall) + if (str_striequal(ext, EXT_QVM) && g_gameinfo.game->funcs->pfnQVMSyscall) { return s_mod_load_qvm(mod); - + } // if DLL else if (str_striequal(ext, EXT_DLL)) { // load DLL - if (!(mod.dll = dlopen(file.c_str(), RTLD_NOW))) { + mod.dll = dlopen(file.c_str(), RTLD_NOW); + if (!mod.dll) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): DLL load failed: {}\n", file, dlerror()); - return false; + goto fail; } // if this DLL is the same as QMM, cancel if (mod.dll == g_gameinfo.qmm_module_ptr) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): DLL is actually QMM?\n", file); - dlclose(mod.dll); - return false; + goto fail; } mod.vmbase = 0; - // if game supports GetGameAPI, look for GetGameAPI function - if (g_gameinfo.game->funcs->pfnGetGameAPI) { - mod_GetGameAPI pfnGGA = (mod_GetGameAPI)dlsym(mod.dll, "GetGameAPI"); - - // try for "GetModuleAPI", which is what OpenJK uses - if (!pfnGGA) { - pfnGGA = (mod_GetGameAPI)dlsym(mod.dll, "GetModuleAPI"); - } - - if (pfnGGA) { - // pass the GetGameAPI function pointer to the game-specific mod load handler - if (g_gameinfo.game->funcs->pfnModLoad && - g_gameinfo.game->funcs->pfnModLoad((void*)pfnGGA, true)) { // true = is_GetGameAPI - return true; - } - else { - LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): \"GetGameAPI\" function failed\n", mod.path); - } - } - else { - LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Unable to find \"GetGameAPI\" function\n", mod.path); - } - } + if (s_mod_load_dll(mod, QMM_API_GETGAMEAPI)) + return true; + if (s_mod_load_dll(mod, QMM_API_GETMODULEAPI)) + return true; + if (s_mod_load_dll(mod, QMM_API_DLLENTRY)) + return true; - // if game supports dllEntry, look for dllEntry function - if (g_gameinfo.game->funcs->pfndllEntry) { - mod_dllEntry pfndllEntry = (mod_dllEntry)dlsym(mod.dll, "dllEntry"); - mod_vmMain pfnvmMain = (mod_vmMain)dlsym(mod.dll, "vmMain"); - - if (pfndllEntry && pfnvmMain) { - if (g_gameinfo.game->funcs->pfnModLoad) { - // pass the vmMain function pointer to the game-specific mod load handler - if (g_gameinfo.game->funcs->pfnModLoad((void*)pfnvmMain, false)) { // false = !is_GetGameAPI - // pass qmm_syscall to mod's dllEntry function - pfndllEntry(qmm_syscall); - return true; - } - else { - LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Mod load failed?\n", mod.path); - } - } - // hack in case there isn't a game-specific dllEntry or ModLoad function - else if (!g_gameinfo.pfnvmMain) { - g_gameinfo.pfnvmMain = pfnvmMain; - } - } - else { - LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Unable to find \"dllEntry\" and/or \"vmMain\" function\n", mod.path); - } - } + LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Unable to locate mod entry point\n", file); + goto fail; + } + else { + LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Unknown mod file format\n", file); } +fail: + if (mod.dll) + dlclose(mod.dll); mod_unload(mod); - - LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Unknown file format\n", file); return false; } -void mod_unload(mod& mod) { +void mod_unload(qmm_mod& mod) { // call the game-specific mod unload callback if (g_gameinfo.game->funcs->pfnModUnload) g_gameinfo.game->funcs->pfnModUnload(); qvm_unload(&mod.vm); if (mod.dll) dlclose(mod.dll); - mod = ::mod(); + mod = qmm_mod(); } @@ -158,7 +122,7 @@ static intptr_t s_mod_qvm_vmmain(intptr_t cmd, ...) { // handle syscalls from the QVM. passed to qvm_load static int s_mod_qvm_syscall(uint8_t* membase, int cmd, int* args) { // if no game-specific qvm handler, we need to error - if (!g_gameinfo.game->funcs->pfnqvmsyscall) { + if (!g_gameinfo.game->funcs->pfnQVMSyscall) { if (!g_gameinfo.is_shutdown) { g_gameinfo.is_shutdown = true; LOG(QMM_LOG_FATAL, "QMM") << fmt::format("s_mod_qvm_syscall({}): No QVM syscall handler found\n", g_gameinfo.game->funcs->pfnEngMsgNames(cmd)); @@ -169,7 +133,7 @@ static int s_mod_qvm_syscall(uint8_t* membase, int cmd, int* args) { // check for plugin qvm function registration if (cmd >= QMM_QVM_FUNC_STARTING_ID && g_registered_qvm_funcs.count(cmd)) { - plugin* p = g_registered_qvm_funcs[cmd]; + qmm_plugin* p = g_registered_qvm_funcs[cmd]; // make sure plugin has the handler function (shouldn't have been registered, but check anyway) if (!p->QMM_QVMHandler) @@ -180,12 +144,12 @@ static int s_mod_qvm_syscall(uint8_t* membase, int cmd, int* args) { } // call the game-specific QVM syscall handler - return g_gameinfo.game->funcs->pfnqvmsyscall(membase, cmd, args); + return g_gameinfo.game->funcs->pfnQVMSyscall(membase, cmd, args); } // load a QVM mod -static bool s_mod_load_qvm(mod& mod) { +static bool s_mod_load_qvm(qmm_mod& mod) { int fpk3 = 0; intptr_t filelen; std::vector filemem; @@ -217,18 +181,18 @@ static bool s_mod_load_qvm(mod& mod) { mod.vmbase = (intptr_t)mod.vm.datasegment; + // store the qvm vmMain pointer as a backup (should get overwritten in game-specific mod load handler) + g_gameinfo.pfnvmMain = s_mod_qvm_vmmain; + // pass the qvm vmMain function pointer to the game-specific mod load handler - if (g_gameinfo.game->funcs->pfnModLoad && - !g_gameinfo.game->funcs->pfnModLoad((void*)s_mod_qvm_vmmain, false)) // false = !is_GetGameAPI + if (!g_gameinfo.game->funcs->pfnModLoad || + !g_gameinfo.game->funcs->pfnModLoad((void*)s_mod_qvm_vmmain, QMM_API_QVM)) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Mod load failed?\n", mod.path); goto fail; } - // hack in case there isn't a game-specific dllEntry or ModLoad function - if (!g_gameinfo.pfnvmMain) { - g_gameinfo.pfnvmMain = s_mod_qvm_vmmain; - } + mod.api = QMM_API_QVM; return true; @@ -236,3 +200,53 @@ static bool s_mod_load_qvm(mod& mod) { mod_unload(mod); return false; } + + +static bool s_mod_load_dll(qmm_mod& mod, APIType api) { + switch (api) { + case QMM_API_GETGAMEAPI: + case QMM_API_GETMODULEAPI: { + // these are together because they work the same, just with a different function name + + // mod load handler is needed for these api types + if (!g_gameinfo.game->funcs->pfnModLoad) + return false; + + // look for GetGameAPI/GetModuleAPI function + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)dlsym(mod.dll, APIType_Function(api)); + if (!pfnGGA) + return false; + + // if mod load handler says good to go, we do too + if (g_gameinfo.game->funcs->pfnModLoad((void*)pfnGGA, api)) { + mod.api = api; + return true; + } + + return false; + } + case QMM_API_DLLENTRY: { + mod_dllEntry pfndllEntry = (mod_dllEntry)dlsym(mod.dll, "dllEntry"); + mod_vmMain pfnvmMain = (mod_vmMain)dlsym(mod.dll, "vmMain"); + if (!pfndllEntry || !pfnvmMain) + return false; + + // store the vmMain pointer as a backup (should get overwritten in game-specific mod load handler) + g_gameinfo.pfnvmMain = pfnvmMain; + + // mod load handler isn't explicitly required for this api type, but pass vmMain to it if it exists + if (!g_gameinfo.game->funcs->pfnModLoad + || g_gameinfo.game->funcs->pfnModLoad((void*)pfnvmMain, api)) + { + // pass qmm_syscall to mod's dllEntry function + pfndllEntry(qmm_syscall); + mod.api = api; + return true; + } + + return false; + } + default: + return false; + }; +} diff --git a/src/plugin.cpp b/src/plugin.cpp index fc9a302..5cb4d6d 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -84,10 +84,10 @@ plugin_globals g_plugin_globals = { QMM_UNUSED, // plugin_result }; -std::vector g_plugins; +std::vector g_plugins; // store registered QVM function IDs for plugins -std::map g_registered_qvm_funcs; +std::map g_registered_qvm_funcs; static int s_next_qvm_func = QMM_QVM_FUNC_STARTING_ID; static plugin_vars s_pluginvars = { @@ -112,7 +112,7 @@ const char* plugin_result_to_str(plugin_res res) { // returns: -1 if failed to load and don't continue, 0 if failed to load and continue, 1 if loaded -int plugin_load(plugin& p, std::string file) { +int plugin_load(qmm_plugin& p, std::string file) { int ret = 0; // if this plugin somehow already has a dll pointer, wipe it first @@ -134,7 +134,7 @@ int plugin_load(plugin& p, std::string file) { } // if this DLL is the same as another loaded plugin, cancel - for (plugin& t : g_plugins) { + for (qmm_plugin& t : g_plugins) { if (p.dll == t.dll) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("plugin_load(\"{}\"): DLL is already loaded as plugin\n", file); // treat this failure specially. this is a valid plugin, but it is already loaded @@ -228,14 +228,14 @@ int plugin_load(plugin& p, std::string file) { } -void plugin_unload(plugin& p) { +void plugin_unload(qmm_plugin& p) { if (p.dll) { if (p.QMM_Detach) p.QMM_Detach(); dlclose(p.dll); } - p = plugin(); + p = qmm_plugin(); } @@ -491,7 +491,7 @@ static void s_plugin_helper_GetConfigString(plugin_id plid [[maybe_unused]], int // char* (*getConfigstring)(int index); // void trap_GetConfigstring(int num, char* buffer, int bufferSize); // some games don't return pointers because of QVM interaction, so if this returns anything but null - // (or true?), we probably are in an api game, and need to get the configstring from the return value + // (or true?), we need to get the configstring from the return value // instead if (buf && buflen) { intptr_t ret = ENG_SYSCALL(QMM_ENG_MSG[QMM_G_GET_CONFIGSTRING], index, buf, buflen); @@ -510,7 +510,7 @@ static void s_plugin_helper_GetConfigString(plugin_id plid [[maybe_unused]], int static int s_plugin_helper_PluginBroadcast(plugin_id plid, const char* message, void* buf, intptr_t buflen) { // count how many plugins were called int total = 0; - for (plugin& p : g_plugins) { + for (qmm_plugin& p : g_plugins) { // skip the calling plugin if (p.plugininfo == (plugin_info*)plid) continue; @@ -535,7 +535,7 @@ static int s_plugin_helper_PluginSend(plugin_id plid, plugin_id to_plid, const c if (plid == to_plid) return 0; - for (plugin& p : g_plugins) { + for (qmm_plugin& p : g_plugins) { // if this is the destination plugin if (p.plugininfo == (plugin_info*)to_plid) { // if the plugin doesn't have the message function @@ -559,7 +559,7 @@ static int s_plugin_helper_QVMRegisterFunc(plugin_id plid) { int ret = 0; // find the calling plugin - for (plugin& p : g_plugins) { + for (qmm_plugin& p : g_plugins) { // found it if (p.plugininfo == (plugin_info*)plid) { // make sure the plugin actually has a QVM handler func