diff --git a/include/game_api.h b/include/game_api.h index 2984dfb..cd6f569 100644 --- a/include/game_api.h +++ b/include/game_api.h @@ -19,11 +19,8 @@ Created By: #include "qmmapi.h" #include "qvm.h" -using msgname_t = const char* (*)(intptr_t); -using mod_load_t = bool (*)(void*); -using mod_unload_t = void (*)(); // some information for each game engine supported by QMM -struct supportedgame_t { +struct supportedgame { const char* dllname; // default dll mod filename const char* qvmname; // default qvm mod filename (NULL = not supported) const char* moddir; // default moddir name @@ -34,21 +31,21 @@ struct supportedgame_t { const char* gamename_short; // short initials for game int* qmm_eng_msgs; // array of engine messages used by QMM int* qmm_mod_msgs; // array of mod messages used by QMM - msgname_t eng_msg_names; // pointer to a function that returns a string for a given engine message - msgname_t mod_msg_names; // pointer to a function that returns a string for a given mod message + const char*(*eng_msg_names)(intptr_t); // pointer to a function that returns a string for a given engine message + const char*(*mod_msg_names)(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) - qvmsyscall_t pfnqvmsyscall; // pointer to a function that handles mod->engine calls from a QVM (NULL = not supported) - mod_dllEntry_t pfndllEntry; // pointer to a function that handles dllEntry entry for a game (NULL = not supported) - mod_GetGameAPI_t pfnGetGameAPI; // pointer to a function that handles GetGameAPI entry for a game (NULL = not supported) - mod_load_t pfnModLoad; // pointer to a function that handles mod loading logic after a DLL is loaded - mod_unload_t 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) + 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*); // pointer to a function that handles mod loading logic after a DLL is loaded + void(*pfnModUnload)(); // pointer to a function that handles mod unloading logic before a DLL is unloaded 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 supportedgame_t g_supportedgames[]; +extern supportedgame g_supportedgames[]; // macros to make game support a bit easier to do // these macros are used in game_api.cpp and game_xyz.cpp @@ -59,25 +56,24 @@ extern supportedgame_t g_supportedgames[]; const char* game##_eng_msg_names(intptr_t); \ const char* game##_mod_msg_names(intptr_t); \ int game##_qvmsyscall(uint8_t*, int, int*); \ - void game##_dllEntry(eng_syscall_t); \ - void* game##_GetGameAPI(void*, void*); \ - bool game##_mod_load(void*); \ - void game##_mod_unload(); + void game##_dllEntry(eng_syscall); \ + void* game##_GetGameAPI(void*, void*); \ + bool game##_mod_load(void*); \ + void game##_mod_unload(); // generate struct info for the short name, messages arrays, and message name functions #define GEN_INFO(game) #game, game##_qmm_eng_msgs, game##_qmm_mod_msgs, game##_eng_msg_names, game##_mod_msg_names // generate struct info for the game-specific entry functions -#define GEN_DLLQVM(game) game##_qvmsyscall, game##_dllEntry, nullptr, game##_mod_load, game##_mod_unload -#define GEN_DLL(game) nullptr, game##_dllEntry, nullptr, game##_mod_load, game##_mod_unload -#define GEN_GGA(game) nullptr, nullptr, game##_GetGameAPI, game##_mod_load, game##_mod_unload +#define GEN_DLLQVM(game) game##_qvmsyscall, game##_dllEntry, nullptr, game##_mod_load, game##_mod_unload +#define GEN_DLL(game) nullptr, game##_dllEntry, nullptr, game##_mod_load, game##_mod_unload +#define GEN_GGA(game) nullptr, nullptr, game##_GetGameAPI, game##_mod_load, game##_mod_unload // generate a case/string line for the message name 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 -enum qmm_eng_msg_t { +enum { // general purpose QMM_G_PRINT, QMM_G_ERROR, QMM_G_ARGV, QMM_G_ARGC, QMM_G_SEND_CONSOLE_COMMAND, QMM_G_GET_CONFIGSTRING, // cvars @@ -87,10 +83,9 @@ enum qmm_eng_msg_t { }; // a list of all the mod messages used by QMM. if you change this, update the GEN_QMM_MSGS macro -enum qmm_mod_msg_t { QMM_GAME_INIT, QMM_GAME_SHUTDOWN, QMM_GAME_CONSOLE_COMMAND, }; +enum { QMM_GAME_INIT, QMM_GAME_SHUTDOWN, QMM_GAME_CONSOLE_COMMAND, }; -// macro to easily output game-specific message values to match the qmm_eng_msg_t and qmm_mod_msg_t enums above -// this macro goes in game_*.cpp +// macro to easily output game-specific message values to match the enums above. this macro goes in game_*.cpp #define GEN_QMM_MSGS(game) \ int game##_qmm_eng_msgs[] = { \ G_PRINT, G_ERROR, G_ARGV, G_ARGC, G_SEND_CONSOLE_COMMAND, G_GET_CONFIGSTRING, \ @@ -129,20 +124,17 @@ constexpr int QMM_MAX_SYSCALL_ARGS = 17; // ----- GetGameAPI stuff ----- // ---------------------------- -// used by GetGameAPI code as a cast for generic syscall/vmmain calls -using pfn_call_t = intptr_t (*)(intptr_t arg0, ...); - // handle calls from QMM and plugins into the engine -#define ROUTE_IMPORT(field, cmd) case cmd: ret = ((pfn_call_t)(orig_import. field))(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16]); break +#define ROUTE_IMPORT(field, cmd) case cmd: ret = ((eng_syscall)(orig_import. field))(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16]); break #define ROUTE_IMPORT_VAR(field, cmd) case cmd: ret = (intptr_t)&(orig_import. field); break // handle calls from QMM and plugins into the mod -#define ROUTE_EXPORT(field, cmd) case cmd: ret = ((pfn_call_t)(orig_export-> field))(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break +#define ROUTE_EXPORT(field, cmd) case cmd: ret = ((mod_vmMain)(orig_export-> field))(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break #define ROUTE_EXPORT_VAR(field, cmd) case cmd: ret = (intptr_t)&(orig_export-> field); break // handle calls from engine or mod into QMM #define GEN_IMPORT(field, cmd) (decltype(qmm_import. field)) +[](intptr_t arg0, intptr_t arg1, intptr_t arg2, intptr_t arg3, intptr_t arg4, intptr_t arg5, intptr_t arg6, intptr_t arg7, intptr_t arg8, intptr_t arg9, intptr_t arg10, intptr_t arg11, intptr_t arg12, intptr_t arg13, intptr_t arg14, intptr_t arg15, intptr_t arg16) { return qmm_syscall(cmd, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); } -#define GEN_EXPORT(field, cmd) (decltype(qmm_export. field)) +[](intptr_t arg0, intptr_t arg1, intptr_t arg2, intptr_t arg3, intptr_t arg4, intptr_t arg5, intptr_t arg6, intptr_t arg7, intptr_t arg8) { cgame_is_QMM_vmMain_call = true; return vmMain(cmd, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } +#define GEN_EXPORT(field, cmd) (decltype(qmm_export. field)) +[](intptr_t arg0, intptr_t arg1, intptr_t arg2, intptr_t arg3, intptr_t arg4, intptr_t arg5, intptr_t arg6, intptr_t arg7, intptr_t arg8) { cgame.is_from_QMM = true; return vmMain(cmd, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } // if the syscall lambda types matter (float args in 64-bit games like Q2R), use these // macros to easily generate a lambda with full return and argument type information: // e.g. GEN_IMPORT_2(G_DEBUGGRAPH, void, float, int) diff --git a/include/main.h b/include/main.h index 61ad883..2adfcfa 100644 --- a/include/main.h +++ b/include/main.h @@ -17,40 +17,50 @@ Created By: #include "game_api.h" // store all currently-loaded game & game engine info -struct game_info_t { +struct gameinfo { std::string exe_path; // full path of running server binary std::string exe_dir; // directory of running server binary std::string exe_file; // filename of running server binary std::string qmm_path; // full path of qmm dll std::string qmm_dir; // directory of qmm dll std::string qmm_file; // filename of qmm dll - std::string moddir; // active mod dir + std::string mod_dir; // active mod dir std::string cfg_path; // qmm config file path - eng_syscall_t pfnsyscall = nullptr; // game-specific wrapper for syscall. given to plugins and called by QMM - mod_vmMain_t pfnvmMain = nullptr; // game-specific wrapper for vmMain. given to plugins and called by QMM - supportedgame_t* game = nullptr; // loaded engine from supported games table from game_api.cpp + 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 void* qmm_module_ptr = nullptr; // qmm module pointer bool isautodetected = false; // was this engine auto-detected? + bool isshutdown = false; // is game shutting down due to G_ERROR? avoids calling G_ERROR again from GAME_SHUTDOWN }; - -extern game_info_t g_gameinfo; +extern gameinfo g_gameinfo; #define QMM_ENG_MSG (g_gameinfo.game->qmm_eng_msgs) #define QMM_MOD_MSG (g_gameinfo.game->qmm_mod_msgs) -#define ENG_SYSCALL g_gameinfo.pfnsyscall +#define ENG_SYSCALL (g_gameinfo.pfnsyscall) // this is used if we couldn't determine a game engine and we have to fail. // G_ERROR appears to be 1 in all supported dllEntry games. they are different in some GetGameAPI games, // but for those we just return nullptr from GetGameAPI constexpr int QMM_FAIL_G_ERROR = 1; -// set to true if a G_ERROR has been triggered, to avoid calling it again from GAME_SHUTDOWN or its ilk (SOF2MP's GAME_GHOUL2_SHUTDOWN, etc) -extern bool g_shutdown; -// flag that is set by GEN_EXPORT macro before calling into vmMain. used to tell if this is a call that -// should be directly routed to the mod or not in some single player games that have game & cgame in the -// same DLL -extern bool cgame_is_QMM_vmMain_call; +// store cgame passthrough stuff +struct cgameinfo { + // store syscall pointer if we need to pass it through to the mod's dllEntry function for games with + // combined game+cgame (singleplayer) + eng_syscall syscall; + // store mod's vmMain function for cgame passthrough + mod_vmMain vmMain; + // flag that is set by GEN_EXPORT macro before calling into vmMain. used to tell if this is a call that + // should be directly routed to the mod or not in some single player games that have game & cgame in the + // same DLL + bool is_from_QMM; + // GAME_SHUTDOWN has been called, but mod DLL was kept loaded so cgame shutdown can run + bool shutdown; +}; +extern cgameinfo cgame; + // engine->mod entry point C_DLLEXPORT intptr_t vmMain(intptr_t cmd, ...); // renamed syscall to qmm_syscall to avoid conflict with POSIX "long syscall(long number, ...)" which has pretty much the same interface diff --git a/include/mod.h b/include/mod.h index 215f217..1919c31 100644 --- a/include/mod.h +++ b/include/mod.h @@ -16,17 +16,17 @@ Created By: #include "qmmapi.h" #include "qvm.h" -struct mod_t { +struct mod { void* dll = nullptr; - qvm_t qvm = {}; + qvm vm = {}; intptr_t vmbase = 0; std::string path; }; -extern mod_t g_mod; +extern mod g_mod; -bool mod_load(mod_t& mod, std::string file); -void mod_unload(mod_t& mod); +bool mod_load(mod& mod, std::string file); +void mod_unload(mod& mod); #endif // QMM2_MOD_H diff --git a/include/osdef.h b/include/osdef.h index 1174b90..e6185d2 100644 --- a/include/osdef.h +++ b/include/osdef.h @@ -24,19 +24,13 @@ Created By: #ifdef _WIN64 #define SUF_DLL "x86_64" -#define SUF_SO "x86_64" #else #define SUF_DLL "x86" -#define SUF_SO "x86" #endif + #define EXT_DLL "dll" -#define EXT_SO "dll" #define EXT_QVM "qvm" -constexpr const unsigned char MAGIC_DLL[] = { 'M', 'Z', 0x90, 0x00 }; -constexpr const unsigned char MAGIC_SO[] = { 'M', 'Z', 0x90, 0x00 }; -constexpr const unsigned char MAGIC_QVM[] = { 'D', 0x14, 'r', 0x12 }; - #define NAKED __declspec(naked) #define PATH_MAX 4096 #define my_vsnprintf _vsnprintf @@ -60,19 +54,13 @@ const char* dlerror(); // this will return the last error from any win32 functi #ifdef __LP64__ #define SUF_DLL "x86_64" -#define SUF_SO "x86_64" #else #define SUF_DLL "i386" -#define SUF_SO "i386" #endif + #define EXT_DLL "so" -#define EXT_SO "so" #define EXT_QVM "qvm" -constexpr const unsigned char MAGIC_DLL[] = { 0x7F, 'E', 'L', 'F' }; -constexpr const unsigned char MAGIC_SO[] = { 0x7F, 'E', 'L', 'F' }; -constexpr const unsigned char MAGIC_QVM[] = { 'D', 0x14, 'r', 0x12 }; - #define NAKED __attribute__((naked)) #define my_vsnprintf vsnprintf void MessageBoxA(void* handle, const char* message, const char* title, int flags); @@ -83,6 +71,8 @@ void MessageBoxA(void* handle, const char* message, const char* title, int flags #endif +#define MOD_DLL SUF_DLL "." EXT_DLL + void* osdef_path_get_qmm_handle(); const char* osdef_path_get_qmm_path(); const char* osdef_path_get_proc_path(); diff --git a/include/plugin.h b/include/plugin.h index 89ec101..8769dd6 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -18,9 +18,9 @@ Created By: #include "qmmapi.h" // QMM_Query -using plugin_query = void (*)(plugininfo_t** pinfo); +using plugin_query = void (*)(plugin_info** pinfo); // QMM_Attach -using plugin_attach = int (*)(eng_syscall_t engfunc, mod_vmMain_t modfunc, pluginres_t* presult, pluginfuncs_t* pluginfuncs, pluginvars_t* pluginvars); +using plugin_attach = int (*)(eng_syscall engfunc, mod_vmMain modfunc, plugin_res* presult, plugin_funcs* pluginfuncs, plugin_vars* pluginvars); // QMM_Detach using plugin_detach = void (*)(); // QMM_vmMain @@ -28,11 +28,11 @@ using plugin_vmmain = intptr_t(*)(intptr_t cmd, intptr_t* args); // QMM_syscall using plugin_syscall = intptr_t(*)(intptr_t cmd, intptr_t* args); // QMM_PluginMessage -using plugin_pluginmessage = void (*)(plid_t from_plid, const char* message, void* buf, intptr_t buflen, int is_broadcast); +using plugin_pluginmessage = void (*)(plugin_id from_plid, const char* message, void* buf, intptr_t buflen, int is_broadcast); // QMM_QVMHandler using plugin_qvmhandler = int (*)(int cmd, int* args); -struct plugin_t { +struct plugin { void* dll = nullptr; std::string path; plugin_query QMM_Query = nullptr; @@ -44,30 +44,30 @@ struct plugin_t { plugin_syscall QMM_syscall_Post = nullptr; plugin_pluginmessage QMM_PluginMessage = nullptr; plugin_qvmhandler QMM_QVMHandler = nullptr; - plugininfo_t* plugininfo = nullptr; + plugin_info* plugininfo = nullptr; }; -struct plugin_globals_t { +struct plugin_globals { intptr_t final_return = 0; intptr_t orig_return = 0; - pluginres_t high_result = QMM_UNUSED; - pluginres_t plugin_result = QMM_UNUSED; + plugin_res high_result = QMM_UNUSED; + plugin_res plugin_result = QMM_UNUSED; }; -extern plugin_globals_t g_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(pluginres_t res); +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_t& p, std::string file); +int plugin_load(plugin& p, std::string file); -void plugin_unload(plugin_t& p); +void plugin_unload(plugin& p); #endif // QMM2_PLUGIN_H diff --git a/include/qmmapi.h b/include/qmmapi.h index 13a1ae5..3efb98d 100644 --- a/include/qmmapi.h +++ b/include/qmmapi.h @@ -32,15 +32,15 @@ Created By: #endif // various function pointer types -typedef intptr_t (*eng_syscall_t)(intptr_t, ...); -typedef intptr_t (*mod_vmMain_t)(intptr_t, ...); -typedef void (*mod_dllEntry_t)(eng_syscall_t); -typedef void* (*mod_GetGameAPI_t)(void*, void*); +typedef intptr_t (*eng_syscall)(intptr_t, ...); +typedef intptr_t (*mod_vmMain)(intptr_t, ...); +typedef void (*mod_dllEntry)(eng_syscall); +typedef void* (*mod_GetGameAPI)(void*, void*); -// major interface version increases with change to the signature of QMM_Query, QMM_Attach, QMM_Detach, pluginfunc_t, or plugininfo_t +// major interface version increases with change to the signature of QMM_Query, QMM_Attach, QMM_Detach, plugin_func, or plugin_info #define QMM_PIFV_MAJOR 4 -// minor interface version increases with trailing addition to pluginfunc_t or plugininfo_t structs -#define QMM_PIFV_MINOR 2 +// minor interface version increases with trailing addition to plugin_func or plugin_info structs +#define QMM_PIFV_MINOR 3 // 2:0 // - removed canpause, loadcmd, unloadcmd from plugininfo_t // - renamed old pause/cmd args to QMM_ functions (iscmd, etc) to "reserved" @@ -66,9 +66,11 @@ typedef void* (*mod_GetGameAPI_t)(void*, void*); // - added QMM_QVM_REGISTER_FUNC, QMM_QVM_EXEC_FUNC, QMM_ARGV2, and QMM_GETCONFIGSTRING2 // - added optional QMM_QVMHandler callback function // - pluginfunc macros now hide PLID arg +// 4:3 +// - changed type names away from those ending with "_t" - added typedefs for old names marked deprecated. define QMM_USE_DEPRECATED_TYPES to use old types without warning // holds plugin info to pass back to QMM -typedef struct plugininfo_s { +typedef struct { intptr_t pifv_major; // major plugin interface version intptr_t pifv_minor; // minor plugin interface version const char* name; // name of plugin @@ -79,11 +81,11 @@ typedef struct plugininfo_s { const char* logtag; // log tag intptr_t reserved1; // reserved intptr_t reserved2; // reserved -} plugininfo_t; +} plugin_info; // "opaque" plugin info pointer to use as an identifier for plugin funcs -typedef plugininfo_t* plid_t; -#define PLID ((plid_t)&g_plugininfo) +typedef plugin_info* plugin_id; +#define PLID ((plugin_id)&g_plugininfo) // log severity for QMM_WRITEQMMLOG enum { @@ -97,16 +99,16 @@ enum { }; // only set QMM_ERROR, QMM_IGNORED, QMM_OVERRIDE, and QMM_SUPERCEDE -typedef enum pluginres_e { +typedef enum { QMM_UNUSED = -2, // default value, output a warning message in logs, do not use, but otherwise functions like QMM_IGNORED QMM_ERROR = -1, // output an error message in logs, but otherwise functions like QMM_IGNORED QMM_IGNORED = 0, // this plugin doesn't need special handling QMM_OVERRIDE, // this plugin has overridden the return value QMM_SUPERCEDE // this plugin has overridden the return value AND wants the original function to not be called -} pluginres_t; +} plugin_res; // macros to help set the plugin result value -#define QMM_SET_RESULT(res) *g_result = (pluginres_t)(res) // set result flag to "res" +#define QMM_SET_RESULT(res) *g_result = (plugin_res)(res) // set result flag to "res" #define QMM_RETURN(res, ret) return (QMM_SET_RESULT(res), (ret)) // set result flag to "res" and return "ret" #define QMM_RET_ERROR(ret) QMM_RETURN(QMM_ERROR, (ret)) // output an error message in logs, but otherwise functions like QMM_IGNORED, and return "ret" #define QMM_RET_IGNORED(ret) QMM_RETURN(QMM_IGNORED, (ret)) // this plugin doesn't need special handling, and return "ret" @@ -114,30 +116,30 @@ typedef enum pluginres_e { #define QMM_RET_SUPERCEDE(ret) QMM_RETURN(QMM_SUPERCEDE, (ret)) // this plugin has overridden the return value AND wants the original function to not be called, and return "ret" // prototype struct for QMM plugin util funcs -typedef struct pluginfuncs_s { - void (*pfnWriteQMMLog)(plid_t plid, const char* text, int severity); // write to the QMM log - char* (*pfnVarArgs)(plid_t plid, const char* format, ...); // simple vsprintf helper with rotating buffer - int (*pfnIsQVM)(plid_t plid); // returns 1 if the mod is QVM - const char* (*pfnEngMsgName)(plid_t plid, intptr_t msg); // get the string name of a syscall code - const char* (*pfnModMsgName)(plid_t plid, intptr_t msg); // get the string name of a vmMain code - intptr_t (*pfnGetIntCvar)(plid_t plid, const char* cvar); // get the int value of a cvar - const char* (*pfnGetStrCvar)(plid_t plid, const char* cvar); // get the str value of a cvar - const char* (*pfnGetGameEngine)(plid_t plid); // return the QMM short code for the game engine - void (*pfnArgv)(plid_t plid, intptr_t argn, char* buf, intptr_t buflen); // call G_ARGV, but can handle both engine styles - const char* (*pfnInfoValueForKey)(plid_t plid, const char* userinfo, const char* key); // same as SDK's Info_ValueForKey - const char* (*pfnConfigGetStr)(plid_t plid, const char* key); // get a string config entry - int (*pfnConfigGetInt)(plid_t plid, const char* key); // get an int config entry - int (*pfnConfigGetBool)(plid_t plid, const char* key); // get a bool config entry - const char** (*pfnConfigGetArrayStr)(plid_t plid, const char* key); // get an array-of-strings config entry (array terminated with a null pointer) - int* (*pfnConfigGetArrayInt)(plid_t plid, const char* key); // get an array-of-ints config entry (array starts with remaining length) - void (*pfnGetConfigString)(plid_t plid, intptr_t index, char* buf, intptr_t buflen); // call G_GET_CONFIGSTRING, but can handle both engine styles - int (*pfnPluginBroadcast)(plid_t plid, const char* message, void* buf, intptr_t buflen); // broadcast a message to plugins' QMM_PluginMessage functions - int (*pfnPluginSend)(plid_t plid, plid_t to_plid, const char* message, void* buf, intptr_t buflen); // send a message to a specific plugin's QMM_PluginMessage function - int (*pfnQVMRegisterFunc)(plid_t plid); // register a new QVM function ID to the calling plugin (0 if unsuccessful) - int (*pfnQVMExecFunc)(plid_t plid, int funcid, int argc, int* argv); // exec a given QVM function function ID - const char* (*pfnArgv2)(plid_t plid, intptr_t argn); // same as pfnArgv except returns value - const char* (*pfnGetConfigString2)(plid_t plid, intptr_t index); // same as pfnGetConfigString except returns value -} pluginfuncs_t; +typedef struct { + void (*pfnWriteQMMLog)(plugin_id plid, const char* text, int severity); // write to the QMM log + char* (*pfnVarArgs)(plugin_id plid, const char* format, ...); // simple vsprintf helper with rotating buffer + int (*pfnIsQVM)(plugin_id plid); // returns 1 if the mod is QVM + const char* (*pfnEngMsgName)(plugin_id plid, intptr_t msg); // get the string name of a syscall code + const char* (*pfnModMsgName)(plugin_id plid, intptr_t msg); // get the string name of a vmMain code + intptr_t (*pfnGetIntCvar)(plugin_id plid, const char* cvar); // get the int value of a cvar + const char* (*pfnGetStrCvar)(plugin_id plid, const char* cvar); // get the str value of a cvar + const char* (*pfnGetGameEngine)(plugin_id plid); // return the QMM short code for the game engine + void (*pfnArgv)(plugin_id plid, intptr_t argn, char* buf, intptr_t buflen); // call G_ARGV, but can handle both engine styles + const char* (*pfnInfoValueForKey)(plugin_id plid, const char* userinfo, const char* key); // same as SDK's Info_ValueForKey + const char* (*pfnConfigGetStr)(plugin_id plid, const char* key); // get a string config entry + int (*pfnConfigGetInt)(plugin_id plid, const char* key); // get an int config entry + int (*pfnConfigGetBool)(plugin_id plid, const char* key); // get a bool config entry + const char** (*pfnConfigGetArrayStr)(plugin_id plid, const char* key); // get an array-of-strings config entry (array terminated with a null pointer) + int* (*pfnConfigGetArrayInt)(plugin_id plid, const char* key); // get an array-of-ints config entry (array starts with remaining length) + void (*pfnGetConfigString)(plugin_id plid, intptr_t index, char* buf, intptr_t buflen); // call G_GET_CONFIGSTRING, but can handle both engine styles + int (*pfnPluginBroadcast)(plugin_id plid, const char* message, void* buf, intptr_t buflen); // broadcast a message to plugins' QMM_PluginMessage functions + int (*pfnPluginSend)(plugin_id plid, plugin_id to_plid, const char* message, void* buf, intptr_t buflen); // send a message to a specific plugin's QMM_PluginMessage function + int (*pfnQVMRegisterFunc)(plugin_id plid); // register a new QVM function ID to the calling plugin (0 if unsuccessful) + int (*pfnQVMExecFunc)(plugin_id plid, int funcid, int argc, int* argv); // exec a given QVM function function ID + const char* (*pfnArgv2)(plugin_id plid, intptr_t argn); // same as pfnArgv except returns value + const char* (*pfnGetConfigString2)(plugin_id plid, intptr_t index); // same as pfnGetConfigString except returns value +} plugin_funcs; // macros for QMM plugin util funcs #define QMM_WRITEQMMLOG(text, severity) (g_pluginfuncs->pfnWriteQMMLog)(PLID, text, severity) // write to the QMM log @@ -164,12 +166,12 @@ typedef struct pluginfuncs_s { #define QMM_GETCONFIGSTRING2(index) (g_pluginfuncs->pfnGetConfigString2)(PLID, index) // same as QMM_GETCONFIGSTRING except returns value // struct of vars for QMM plugin utils -typedef struct pluginvars_s { +typedef struct { intptr_t vmbase; // base address of the QVM memory block (automatically added to pointer args in syscalls) intptr_t* preturn; // pointer to an int that holds the current value to be returned from a function call (updated by QMM_OVERRIDE/QMM_SUPERCEDE in all hooks) intptr_t* porigreturn; // pointer to an int that holds the real mod/engine return value (if called, only available in _Post hooks) - pluginres_t* phighresult; // highest result so far (only tracks results from Pre hooks) -} pluginvars_t; + plugin_res* phighresult; // highest result so far (only tracks results from Pre hooks) +} plugin_vars; // macros for QMM plugin vars #define QMM_VAR_RETURN(cast) ((cast)*(g_pluginvars->preturn)) // get the value to be passed to the caller (from override/supercede or original call), with given cast @@ -185,12 +187,12 @@ typedef struct pluginvars_s { #define SETPTR(ptr, cast) ((ptr) ? (cast)((intptr_t)(ptr) - g_pluginvars->vmbase) : NULL) // convert "ptr" from a real pointer to a QVM pointer, and cast to "cast" type // plugin use only -extern plugininfo_t g_plugininfo; // set '*pinfo' to &g_plugininfo in QMM_Query -extern eng_syscall_t g_syscall; // set to 'engfunc' in QMM_Attach -extern mod_vmMain_t g_vmMain; // set to 'modfunc' in QMM_Attach -extern pluginres_t* g_result; // set to 'presult' in QMM_Attach -extern pluginfuncs_t* g_pluginfuncs; // set to 'pluginfuncs' in QMM_Attach -extern pluginvars_t* g_pluginvars; // set to 'pluginvars' in QMM_Attach +extern plugin_info g_plugininfo; // set '*pinfo' to &g_plugininfo in QMM_Query +extern eng_syscall g_syscall; // set to 'engfunc' in QMM_Attach +extern mod_vmMain g_vmMain; // set to 'modfunc' in QMM_Attach +extern plugin_res* g_result; // set to 'presult' in QMM_Attach +extern plugin_funcs* g_pluginfuncs; // set to 'pluginfuncs' in QMM_Attach +extern plugin_vars* g_pluginvars; // set to 'pluginvars' in QMM_Attach #define QMM_GIVE_PINFO() *pinfo = &g_plugininfo #define QMM_SAVE_VARS() do { \ @@ -202,14 +204,14 @@ extern pluginvars_t* g_pluginvars; // set to 'pluginvars' in QMM_Attach } while(0) // prototypes for entry points in the plugin -C_DLLEXPORT void QMM_Query(plugininfo_t** pinfo); -C_DLLEXPORT int QMM_Attach(eng_syscall_t engfunc, mod_vmMain_t modfunc, pluginres_t* presult, pluginfuncs_t* pluginfuncs, pluginvars_t* pluginvars); +C_DLLEXPORT void QMM_Query(plugin_info** pinfo); +C_DLLEXPORT int QMM_Attach(eng_syscall engfunc, mod_vmMain modfunc, plugin_res* presult, plugin_funcs* pluginfuncs, plugin_vars* pluginvars); C_DLLEXPORT void QMM_Detach(); C_DLLEXPORT intptr_t QMM_vmMain(intptr_t cmd, intptr_t* args); C_DLLEXPORT intptr_t QMM_vmMain_Post(intptr_t cmd, intptr_t* args); C_DLLEXPORT intptr_t QMM_syscall(intptr_t cmd, intptr_t* args); C_DLLEXPORT intptr_t QMM_syscall_Post(intptr_t cmd, intptr_t* args); -C_DLLEXPORT void QMM_PluginMessage(plid_t from_plid, const char* message, void* buf, intptr_t buflen, int is_broadcast); +C_DLLEXPORT void QMM_PluginMessage(plugin_id from_plid, const char* message, void* buf, intptr_t buflen, int is_broadcast); C_DLLEXPORT int QMM_QVMHandler(int func, int* args); // Some helpful macros assuming you've stored entity/client info in G_LOCATE_GAME_DATA @@ -218,4 +220,20 @@ C_DLLEXPORT int QMM_QVMHandler(int func, int* args); #define CLIENT_FROM_NUM(index) ((gclient_t*)((unsigned char*)g_clients + g_clientsize * (index))) // get a gclient_t* by client number (check g_clients for NULL first) #define NUM_FROM_CLIENT(client) ((int)((unsigned char*)(client) - (unsigned char*)g_clients) / g_clientsize) // get a client number by gclient_t* (check g_clients for NULL g_clientsize for 0 first) +#ifdef QMM_USE_DEPRECATED_TYPES +#define DEPRECATE_TYPE(new_type, old_type) typedef new_type old_type +#else +#define DEPRECATE_TYPE(new_type, old_type) [[deprecated("Use '" #new_type "' instead, or #define QMM_USE_DEPRECATED_TYPES")]] typedef new_type old_type +#endif + +DEPRECATE_TYPE(eng_syscall, eng_syscall_t); +DEPRECATE_TYPE(mod_vmMain, mod_vmMain_t); +DEPRECATE_TYPE(mod_dllEntry, mod_dllEntry_t); +DEPRECATE_TYPE(mod_GetGameAPI, mod_GetGameAPI_t); +DEPRECATE_TYPE(plugin_info, plugininfo_t); +DEPRECATE_TYPE(plugin_id, plid_t); +DEPRECATE_TYPE(plugin_res, pluginres_t); +DEPRECATE_TYPE(plugin_funcs, pluginfuncs_t); +DEPRECATE_TYPE(plugin_vars, pluginvars_t); + #endif // QMM2_QMMAPI_H diff --git a/include/qvm.h b/include/qvm.h index 044ce00..c73fb1a 100644 --- a/include/qvm.h +++ b/include/qvm.h @@ -38,7 +38,7 @@ Created By: #define QVM_PUSH(v) --opstack; opstack[0] = (v) // move instruction pointer to a given index, masked to code segment -#define QVM_JUMP(x) opptr = qvm->codesegment + ((x) & codemask) +#define QVM_JUMP(x) opptr = codesegment + ((x) & codemask) // branch comparisons // signed integer comparison @@ -61,10 +61,10 @@ Created By: #define QVM_SFOP(o) *(float*)&opstack[0] = o *(float*)&opstack[0] // function to receive syscalls (engine traps) out of VM -typedef int (*qvmsyscall_t)(uint8_t* membase, int cmd, int* args); +typedef int (*qvm_syscall)(uint8_t* membase, int cmd, int* args); // list of VM instructions -typedef enum qvmopcode_e { +typedef enum { QVM_OP_UNDEF, QVM_OP_NOP, QVM_OP_BREAK, @@ -127,19 +127,19 @@ typedef enum qvmopcode_e { QVM_OP_CVFI, QVM_OP_NUM_OPS, -} qvmopcode_t; +} qvm_opcode; // array of strings of opcode names -extern const char* opcodename[]; +extern const char* qvm_opcodename[]; // a single opcode in memory -typedef struct qvmop_s { - qvmopcode_t op; +typedef struct { + qvm_opcode op; int param; -} qvmop_t; +} qvm_op; // QVM file header -typedef struct qvmheader_s { +typedef struct { uint32_t magic; uint32_t instructioncount; uint32_t codeoffset; @@ -148,29 +148,29 @@ typedef struct qvmheader_s { uint32_t datalen; uint32_t litlen; uint32_t bsslen; -} qvmheader_t; +} qvm_header; // allocator type for custom allocation -typedef struct qvm_alloc_s { +typedef struct { void* (*alloc)(ptrdiff_t size, void* ctx); void (*free)(void* ptr, ptrdiff_t size, void* ctx); void* ctx; -} qvm_alloc_t; +} qvm_alloc; // default vm allocator (uses malloc/free) -extern qvm_alloc_t qvm_allocator_default; +extern qvm_alloc qvm_allocator_default; // all the info for a single QVM object -typedef struct qvm_s { +typedef struct { // syscall - qvmsyscall_t qvmsyscall; // function that will handle syscalls and adjust pointer arguments + qvm_syscall syscall; // function that will handle syscalls and adjust pointer arguments // memory uint8_t* memory; // main block of memory size_t memorysize; // size of memory block // segments (into memory block) - qvmop_t* codesegment; // code segment, each op is 8 bytes (4 op, 4 param) + qvm_op* codesegment; // code segment, each op is 8 bytes (4 op, 4 param) uint8_t* datasegment; // data segment, partially filled on load // segment sizes @@ -186,9 +186,9 @@ typedef struct qvm_s { // extra size_t filesize; // .qvm file size - qvm_alloc_t* allocator; // allocator + qvm_alloc* allocator; // allocator int verify_data; // verify data access is inside the memory block -} qvm_t; +} qvm; #ifdef __cplusplus extern "C" { @@ -197,25 +197,25 @@ extern "C" { /** * Create and initialize a new VM from a QVM file * -* @param [qvm_t*] qvm - Pointer to qvm_t object to store VM information +* @param [qvm*] qvm - Pointer to qvm_t object to store VM information * @param [const uint8_t*] filemem - Buffer with QVM file contents * @param [size_t] filesize - Size of the filemem buffer -* @param [qvmsyscall_t] qvmsyscall - Function to be called for engine traps +* @param [qvm_syscall] qvmsyscall - Function to be called for engine traps * @param [int] verify_data - (Boolean) Should data segment reads and writes be validated? -* @param [qvm_alloc_t*] allocator - Pointer to a qvm_alloc_t object which contains custom alloc/free function pointers (pass NULL for default) +* @param [qvm_alloc*] allocator - Pointer to a qvm_alloc object which contains custom alloc/free function pointers (pass NULL for default) * @returns [int] - (Boolean) 1 if success, 0 if failure */ -int qvm_load(qvm_t* qvm, const uint8_t* filemem, size_t filesize, qvmsyscall_t qvmsyscall, int verify_data, qvm_alloc_t* allocator); +int qvm_load(qvm* vm, const uint8_t* filemem, size_t filesize, qvm_syscall qvmsyscall, int verify_data, qvm_alloc* allocator); /** * Begin execution in a VM * -* @param [qvm_t*] qvm - Pointer to qvm_t object to execute +* @param [qvm*] qvm - Pointer to qvm_t object to execute * @param [int] argc - Number of arguments to pass to VM entry point * @param [int*] argv - Array of arguments to pass to VM entry point * @returns [int] - Return value from VM entry point */ -int qvm_exec(qvm_t* qvm, int argc, int* argv); +int qvm_exec(qvm* vm, int argc, int* argv); /** * Begin execution in a VM at a given instruction @@ -226,14 +226,14 @@ int qvm_exec(qvm_t* qvm, int argc, int* argv); * @param [int*] argv - Array of arguments to pass to VM entry point * @returns [int] - Return value from VM entry point */ -int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv); +int qvm_exec_ex(qvm* vm, size_t instruction, int argc, int* argv); /** * Unload a VM * * @param [qvm_t*] qvm - Pointer to qvm_t object to unload */ -void qvm_unload(qvm_t* qvm); +void qvm_unload(qvm* vm); #ifdef __cplusplus } diff --git a/src/game_api.cpp b/src/game_api.cpp index 1b22de1..81ba3c3 100644 --- a/src/game_api.cpp +++ b/src/game_api.cpp @@ -38,57 +38,50 @@ GEN_EXTS(STEF2); GEN_EXTS(STVOYSP); // add your game's info data here -supportedgame_t g_supportedgames[] = { +supportedgame g_supportedgames[] = { // mod filename qvm mod filename default moddir full gamename exe hints msgs/short name entry procs #syscall#vmmain // vmMain games - { "qagame" SUF_DLL, "vm/qagame.qvm", "baseq3", "Quake 3 Arena", { "q3", "quake3" }, GEN_INFO(Q3A), GEN_DLLQVM(Q3A), 13, 4 }, - { "qagame" SUF_DLL, "vm/qagame.qvm", "baseef", "Star Trek Voyager: Elite Force (Holomatch)", { "stvoy" }, GEN_INFO(STVOYHM), GEN_DLLQVM(STVOYHM),13, 3 }, - { "qagame" SUF_DLL, nullptr, ".", "Return to Castle Wolfenstein (SP)", { "sp" }, GEN_INFO(RTCWSP), GEN_DLL(RTCWSP), 13, 5 }, - { "jampgame" SUF_DLL, nullptr, "base", "Jedi Knight: Jedi Academy (MP)", { "ja" }, GEN_INFO(JAMP), GEN_DLL(JAMP), 13, 6 }, - { "jk2mpgame" SUF_DLL, "vm/jk2mpgame.qvm", "base", "Jedi Knight 2: Jedi Outcast (MP)", { "jk2" }, GEN_INFO(JK2MP), GEN_DLLQVM(JK2MP), 13, 3 }, - { "sof2mp_game" SUF_DLL,"vm/sof2mp_game.qvm","base/mp", "Soldier of Fortune 2: Double Helix (MP)", { "mp" }, GEN_INFO(SOF2MP), GEN_DLLQVM(SOF2MP), 13, 6 }, -// COD, RTCWMP & WET filename changes on linux + { "qagame" MOD_DLL, "vm/qagame.qvm", "baseq3", "Quake 3 Arena", { "q3", "quake3" }, GEN_INFO(Q3A), GEN_DLLQVM(Q3A), 13, 4 }, + { "qagame" MOD_DLL, "vm/qagame.qvm", "baseef", "Star Trek Voyager: Elite Force (Holomatch)", { "stvoy" }, GEN_INFO(STVOYHM), GEN_DLLQVM(STVOYHM),13, 3 }, + { "qagame" MOD_DLL, nullptr, ".", "Return to Castle Wolfenstein (SP)", { "sp" }, GEN_INFO(RTCWSP), GEN_DLL(RTCWSP), 13, 5 }, + { "jk2mpgame" MOD_DLL, "vm/jk2mpgame.qvm", "base", "Jedi Knight 2: Jedi Outcast (MP)", { "jk2" }, GEN_INFO(JK2MP), GEN_DLLQVM(JK2MP), 13, 3 }, + { "sof2mp_game" MOD_DLL,"vm/sof2mp_game.qvm","base/mp", "Soldier of Fortune 2: Double Helix (MP)", { "mp" }, GEN_INFO(SOF2MP), GEN_DLLQVM(SOF2MP), 13, 6 }, + { "jampgame" MOD_DLL, nullptr, "base", "Jedi Knight: Jedi Academy (MP)", { "ja" }, GEN_INFO(JAMP), GEN_DLL(JAMP), 13, 6 }, + // COD, RTCWMP & WET filename changes on linux #if defined(_WIN32) - { "qagame_mp_" SUF_DLL, nullptr, "etmain", "Wolfenstein: Enemy Territory", { "et" }, GEN_INFO(WET), GEN_DLL(WET), 13, 5 }, - { "qagame_mp_" SUF_DLL, nullptr, "main", "Return to Castle Wolfenstein (MP)", { "mp" }, GEN_INFO(RTCWMP), GEN_DLL(RTCWMP), 13, 5 }, - { "game_mp_" SUF_DLL, nullptr, "Main", "Call of Duty (MP)", { "codmp", "cod_" }, GEN_INFO(CODMP), GEN_DLL(CODMP), 8, 4 }, - { "uo_game_mp_" SUF_DLL,nullptr, "uo", "Call of Duty: United Offensive (MP)", { "coduo" }, GEN_INFO(CODUOMP), GEN_DLL(CODUOMP), 8, 4 }, + { "qagame_mp_" MOD_DLL, nullptr, "etmain", "Wolfenstein: Enemy Territory", { "et" }, GEN_INFO(WET), GEN_DLL(WET), 13, 5 }, + { "qagame_mp_" MOD_DLL, nullptr, "main", "Return to Castle Wolfenstein (MP)", { "mp" }, GEN_INFO(RTCWMP), GEN_DLL(RTCWMP), 13, 5 }, + { "game_mp_" MOD_DLL, nullptr, "Main", "Call of Duty (MP)", { "codmp", "cod_" }, GEN_INFO(CODMP), GEN_DLL(CODMP), 8, 4 }, + { "uo_game_mp_" MOD_DLL,nullptr, "uo", "Call of Duty: United Offensive (MP)", { "coduo" }, GEN_INFO(CODUOMP), GEN_DLL(CODUOMP), 8, 4 }, // allow a user to choose "COD11MP" manually if they are playing an old version of CoD (fake exe hints so it won't auto-detect) - { "game_mp_" SUF_DLL, nullptr, "Main", "Call of Duty v1.1 (MP)", { "zzz_no_auto" }, GEN_INFO(COD11MP), GEN_DLL(COD11MP), 8, 4 }, + { "game_mp_" MOD_DLL, nullptr, "Main", "Call of Duty v1.1 (MP)", { "zzz_no_auto" }, GEN_INFO(COD11MP), GEN_DLL(COD11MP), 8, 4 }, #elif defined(__linux__) - { "qagame.mp." SUF_DLL, nullptr, "etmain", "Wolfenstein: Enemy Territory", { "et" }, GEN_INFO(WET), GEN_DLL(WET), 13, 5 }, - { "qagame.mp." SUF_DLL, nullptr, "main", "Return to Castle Wolfenstein (MP)", { "mp" }, GEN_INFO(RTCWMP), GEN_DLL(RTCWMP), 13, 5 }, - { "game.mp." SUF_DLL, nullptr, "Main", "Call of Duty (MP)", { "codmp", "cod_" }, GEN_INFO(CODMP), GEN_DLL(CODMP), 8, 4 }, - { "game.mp.uo." SUF_DLL,nullptr, "uo", "Call of Duty: United Offensive (MP)", { "coduo" }, GEN_INFO(CODUOMP), GEN_DLL(CODUOMP), 8, 4 }, + { "qagame.mp." MOD_DLL, nullptr, "etmain", "Wolfenstein: Enemy Territory", { "et" }, GEN_INFO(WET), GEN_DLL(WET), 13, 5 }, + { "qagame.mp." MOD_DLL, nullptr, "main", "Return to Castle Wolfenstein (MP)", { "mp" }, GEN_INFO(RTCWMP), GEN_DLL(RTCWMP), 13, 5 }, + { "game.mp." MOD_DLL, nullptr, "Main", "Call of Duty (MP)", { "codmp", "cod_" }, GEN_INFO(CODMP), GEN_DLL(CODMP), 8, 4 }, + { "game.mp.uo." MOD_DLL,nullptr, "uo", "Call of Duty: United Offensive (MP)", { "coduo" }, GEN_INFO(CODUOMP), GEN_DLL(CODUOMP), 8, 4 }, // allow a user to choose "COD11MP" manually if they are playing an old version of CoD (fake exe hints so it won't auto-detect) - { "game.mp." SUF_DLL, nullptr, "Main", "Call of Duty v1.1 (MP)", { "zzz_no_auto" }, GEN_INFO(COD11MP), GEN_DLL(COD11MP), 8, 4 }, + { "game.mp." MOD_DLL, nullptr, "Main", "Call of Duty v1.1 (MP)", { "zzz_no_auto" }, GEN_INFO(COD11MP), GEN_DLL(COD11MP), 8, 4 }, #endif -// don't include CoD single players in linux -/* -#if defined(_WIN32) - { "game" SUF_DLL, nullptr, ".", "Call of Duty (SP)", { "cod" }, GEN_INFO(CODSP), GEN_DLL(CODSP), -1, -1 }, - { "uo_game" SUF_DLL, nullptr, ".", "Call of Duty: United Offensive (SP)", { "coduo" }, GEN_INFO(CODUOSP), GEN_DLL(CODUOSP), -1, -1 }, -#endif -*/ // GetGameAPI games - { "game" SUF_DLL, nullptr, "baseq2", "Quake 2", { "q2", "quake2" }, GEN_INFO(QUAKE2), GEN_GGA(QUAKE2), 7, 3 }, - { "game" SUF_DLL, nullptr, "base", "Star Trek: Elite Force II", { "ef" }, GEN_INFO(STEF2), GEN_GGA(STEF2), 17, 4 }, - { "game" SUF_DLL, nullptr, "base", "SiN", { "sin" }, GEN_INFO(SIN), GEN_GGA(SIN), 10, 3 }, - { "game" SUF_DLL, nullptr, ".", "Soldier of Fortune 2: Double Helix (SP)", { "sof2" }, GEN_INFO(SOF2SP), GEN_GGA(SOF2SP), -1, -1 }, - { "jk2game" SUF_DLL, nullptr, ".", "Jedi Knight 2: Jedi Outcast (SP)", { "jk2" }, GEN_INFO(JK2SP), GEN_GGA(JK2SP), 13, 9 }, - { "jagame" SUF_DLL, nullptr, ".", "Jedi Knight: Jedi Academy (SP)", { "ja" }, GEN_INFO(JASP), GEN_GGA(JASP), 13, 9 }, - { "efgame" SUF_DLL, nullptr, ".", "Star Trek Voyager: Elite Force (SP)", { "stvoy" }, GEN_INFO(STVOYSP), GEN_GGA(STVOYSP), 13, 9 }, + { "game" MOD_DLL, nullptr, "baseq2", "Quake 2", { "q2", "quake2" }, GEN_INFO(QUAKE2), GEN_GGA(QUAKE2), 7, 3 }, + { "game" MOD_DLL, nullptr, "base", "Star Trek: Elite Force II", { "ef" }, GEN_INFO(STEF2), GEN_GGA(STEF2), 17, 4 }, + { "game" MOD_DLL, nullptr, "base", "SiN", { "sin" }, GEN_INFO(SIN), GEN_GGA(SIN), 10, 3 }, + { "game" MOD_DLL, nullptr, ".", "Soldier of Fortune 2: Double Helix (SP)", { "sof2" }, GEN_INFO(SOF2SP), GEN_GGA(SOF2SP), -1, -1 }, // OpenMOHAA adds 64-bit MoH support but the API is very different, so disable it for now #if !defined(_WIN64) && !defined(__LP64__) - { "game" SUF_DLL, nullptr, "main", "Medal of Honor: Allied Assault", { "mohaa" }, GEN_INFO(MOHAA), GEN_GGA(MOHAA), 9, 7 }, - { "game" SUF_DLL, nullptr, "mainta", "Medal of Honor: Spearhead", { "spear" }, GEN_INFO(MOHSH), GEN_GGA(MOHSH), 9, 7 }, - { "game" SUF_DLL, nullptr, "maintt", "Medal of Honor: Breakthrough", { "break" }, GEN_INFO(MOHBT), GEN_GGA(MOHBT), 9, 7 }, + { "game" MOD_DLL, nullptr, "main", "Medal of Honor: Allied Assault", { "mohaa" }, GEN_INFO(MOHAA), GEN_GGA(MOHAA), 9, 7 }, + { "game" MOD_DLL, nullptr, "mainta", "Medal of Honor: Spearhead", { "spear" }, GEN_INFO(MOHSH), GEN_GGA(MOHSH), 9, 7 }, + { "game" MOD_DLL, nullptr, "maintt", "Medal of Honor: Breakthrough", { "break" }, GEN_INFO(MOHBT), GEN_GGA(MOHBT), 9, 7 }, #endif -// Q2R only exists for 64-bit Windows (and no dedicated server) + { "jk2game" MOD_DLL, nullptr, ".", "Jedi Knight 2: Jedi Outcast (SP)", { "jk2" }, GEN_INFO(JK2SP), GEN_GGA(JK2SP), 13, 9 }, + { "jagame" MOD_DLL, nullptr, ".", "Jedi Knight: Jedi Academy (SP)", { "ja" }, GEN_INFO(JASP), GEN_GGA(JASP), 13, 9 }, + { "efgame" MOD_DLL, nullptr, ".", "Star Trek Voyager: Elite Force (SP)", { "stvoy" }, GEN_INFO(STVOYSP), GEN_GGA(STVOYSP), 13, 9 }, + // Q2R only exists for 64-bit Windows (and no dedicated server) #if defined(_WIN64) - { "game_x64", nullptr, "baseq2", "Quake 2 Remastered", { "quake2ex" }, GEN_INFO(Q2R), GEN_GGA(Q2R), 9, 6 }, + { "game_x64.dll", nullptr, "baseq2", "Quake 2 Remastered", { "quake2ex" }, GEN_INFO(Q2R), GEN_GGA(Q2R), 9, 6 }, #endif { nullptr, } diff --git a/src/game_cod11mp.cpp b/src/game_cod11mp.cpp index ef217af..8851617 100644 --- a/src/game_cod11mp.cpp +++ b/src/game_cod11mp.cpp @@ -22,10 +22,10 @@ GEN_QMM_MSGS(COD11MP); GEN_EXTS(COD11MP); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -100,7 +100,7 @@ intptr_t COD11MP_vmMain(intptr_t cmd, ...) { } -void COD11MP_dllEntry(eng_syscall_t syscall) { +void COD11MP_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("COD11MP_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -117,7 +117,7 @@ void COD11MP_dllEntry(eng_syscall_t syscall) { bool COD11MP_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } diff --git a/src/game_codmp.cpp b/src/game_codmp.cpp index d406bd9..d11d4d0 100644 --- a/src/game_codmp.cpp +++ b/src/game_codmp.cpp @@ -27,10 +27,10 @@ GEN_QMM_MSGS(CODMP); GEN_EXTS(CODMP); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -105,7 +105,7 @@ intptr_t CODMP_vmMain(intptr_t cmd, ...) { } -void CODMP_dllEntry(eng_syscall_t syscall) { +void CODMP_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODMP_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -122,7 +122,7 @@ void CODMP_dllEntry(eng_syscall_t syscall) { bool CODMP_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } diff --git a/src/game_coduomp.cpp b/src/game_coduomp.cpp index 5d87cef..aad2557 100644 --- a/src/game_coduomp.cpp +++ b/src/game_coduomp.cpp @@ -27,10 +27,10 @@ GEN_QMM_MSGS(CODUOMP); GEN_EXTS(CODUOMP); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -105,7 +105,7 @@ intptr_t CODUOMP_vmMain(intptr_t cmd, ...) { } -void CODUOMP_dllEntry(eng_syscall_t syscall) { +void CODUOMP_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("CODUOMP_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -122,7 +122,7 @@ void CODUOMP_dllEntry(eng_syscall_t syscall) { bool CODUOMP_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } diff --git a/src/game_jamp.cpp b/src/game_jamp.cpp index cf07fd0..05ba5c6 100644 --- a/src/game_jamp.cpp +++ b/src/game_jamp.cpp @@ -23,10 +23,10 @@ GEN_QMM_MSGS(JAMP); GEN_EXTS(JAMP); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -101,7 +101,7 @@ intptr_t JAMP_vmMain(intptr_t cmd, ...) { } -void JAMP_dllEntry(eng_syscall_t syscall) { +void JAMP_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JAMP_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -118,7 +118,7 @@ void JAMP_dllEntry(eng_syscall_t syscall) { bool JAMP_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } diff --git a/src/game_jasp.cpp b/src/game_jasp.cpp index 234e0eb..659b466 100644 --- a/src/game_jasp.cpp +++ b/src/game_jasp.cpp @@ -176,7 +176,7 @@ static void JASP_Init(const char* mapname, const char* spawntarget, int checkSum s_subbsp_entity_tokens[-1] = util_parse_entstring(entstring); s_tokencount[-1] = 0; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_INIT, mapname, spawntarget, checkSum, entstring, levelTime, randomSeed, globalTime, eSavedGameJustLoaded, qbLoadTransition); } @@ -558,8 +558,8 @@ void* JASP_GetGameAPI(void* import, void*) { bool JASP_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; - orig_export = (game_export_t*)mod_GetGameAPI(&qmm_import, nullptr); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; + orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); return !!orig_export; } diff --git a/src/game_jk2mp.cpp b/src/game_jk2mp.cpp index af32f3c..2a93bad 100644 --- a/src/game_jk2mp.cpp +++ b/src/game_jk2mp.cpp @@ -23,10 +23,10 @@ GEN_QMM_MSGS(JK2MP); GEN_EXTS(JK2MP); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -107,7 +107,7 @@ intptr_t JK2MP_vmMain(intptr_t cmd, ...) { } -void JK2MP_dllEntry(eng_syscall_t syscall) { +void JK2MP_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("JK2MP_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -124,7 +124,7 @@ void JK2MP_dllEntry(eng_syscall_t syscall) { bool JK2MP_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } diff --git a/src/game_jk2sp.cpp b/src/game_jk2sp.cpp index 153cd47..8a28852 100644 --- a/src/game_jk2sp.cpp +++ b/src/game_jk2sp.cpp @@ -146,7 +146,7 @@ static void JK2SP_Init(const char* mapname, const char* spawntarget, int checkSu s_entity_tokens = util_parse_entstring(entstring); s_tokencount = 0; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_INIT, mapname, spawntarget, checkSum, entstring, levelTime, randomSeed, globalTime, eSavedGameJustLoaded, qbLoadTransition); } @@ -480,8 +480,8 @@ void* JK2SP_GetGameAPI(void* import, void*) { bool JK2SP_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; - orig_export = (game_export_t*)mod_GetGameAPI(&qmm_import, nullptr); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; + orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); return !!orig_export; } diff --git a/src/game_mohaa.cpp b/src/game_mohaa.cpp index 25147b3..bf8e219 100644 --- a/src/game_mohaa.cpp +++ b/src/game_mohaa.cpp @@ -217,14 +217,14 @@ static void MOHAA_SpawnEntities(char* entstring, int levelTime) { s_entity_tokens = util_parse_entstring(entstring); s_tokencount = 0; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_SPAWN_ENTITIES, entstring, levelTime); } // at least one of first four args is a float (see big comment at top of game_q2r.cpp), so use specific types static void MOHAA_DebugCircle(float* arg0, float arg1, float arg2, float arg3, float arg4, float arg5, qboolean arg6) { - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_DEBUG_CIRCLE, arg0, arg1, arg2, arg3, arg4, arg5, arg6); } @@ -754,8 +754,8 @@ void* MOHAA_GetGameAPI(void* import, void*) { bool MOHAA_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; - orig_export = (game_export_t*)mod_GetGameAPI(&qmm_import, nullptr); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; + orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); return !!orig_export; } diff --git a/src/game_mohbt.cpp b/src/game_mohbt.cpp index 3f962de..e494fb3 100644 --- a/src/game_mohbt.cpp +++ b/src/game_mohbt.cpp @@ -225,14 +225,14 @@ static void MOHBT_SpawnEntities(char* entstring, int levelTime) { s_entity_tokens = util_parse_entstring(entstring); s_tokencount = 0; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_SPAWN_ENTITIES, entstring, levelTime); } // at least one of first four args is a float (see big comment at top of game_q2r.cpp), so use specific types static void MOHBT_DebugCircle(float* arg0, float arg1, float arg2, float arg3, float arg4, float arg5, qboolean arg6) { - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_DEBUG_CIRCLE, arg0, arg1, arg2, arg3, arg4, arg5, arg6); } @@ -793,8 +793,8 @@ void* MOHBT_GetGameAPI(void* import, void*) { bool MOHBT_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; - orig_export = (game_export_t*)mod_GetGameAPI(&qmm_import, nullptr); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; + orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); return !!orig_export; } diff --git a/src/game_mohsh.cpp b/src/game_mohsh.cpp index f07bb9c..e982b33 100644 --- a/src/game_mohsh.cpp +++ b/src/game_mohsh.cpp @@ -225,14 +225,14 @@ static void MOHSH_SpawnEntities(char* entstring, int levelTime) { s_entity_tokens = util_parse_entstring(entstring); s_tokencount = 0; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_SPAWN_ENTITIES, entstring, levelTime); } // at least one of first four args is a float (see big comment at top of game_q2r.cpp), so use specific types static void MOHSH_DebugCircle(float* arg0, float arg1, float arg2, float arg3, float arg4, float arg5, qboolean arg6) { - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_DEBUG_CIRCLE, arg0, arg1, arg2, arg3, arg4, arg5, arg6); } @@ -793,8 +793,8 @@ void* MOHSH_GetGameAPI(void* import, void*) { bool MOHSH_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; - orig_export = (game_export_t*)mod_GetGameAPI(&qmm_import, nullptr); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; + orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); return !!orig_export; } diff --git a/src/game_q2r.cpp b/src/game_q2r.cpp index 3d3f918..cd8e730 100644 --- a/src/game_q2r.cpp +++ b/src/game_q2r.cpp @@ -152,7 +152,7 @@ static bool Q2R_ClientConnect(edict_t* ent, char* userinfo, const char* social_i else s_userinfo[clientnum] = userinfo; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; return (bool)vmMain(GAME_CLIENT_CONNECT, ent, userinfo, social_id, isBot); } @@ -168,7 +168,7 @@ static void Q2R_ClientUserinfoChanged(edict_t* ent, const char* userinfo) { else s_userinfo[clientnum] = userinfo; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_CLIENT_USERINFO_CHANGED, ent, userinfo); } @@ -181,7 +181,7 @@ static void Q2R_SpawnEntities(const char* mapname, const char* entstring, const s_entity_tokens = util_parse_entstring(entstring); s_tokencount = 0; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_SPAWN_ENTITIES, mapname, entstring, spawnpoint); } @@ -589,7 +589,6 @@ void* Q2R_GetGameAPI(void* import, void*) { qmm_import.tick_rate = orig_import.tick_rate; qmm_import.frame_time_s = orig_import.frame_time_s; qmm_import.frame_time_ms = orig_import.frame_time_ms; - // qmm_import.sound = orig_import.sound; // pointer to wrapper vmMain function that calls actual mod func from orig_export g_gameinfo.pfnvmMain = Q2R_vmMain; @@ -607,8 +606,8 @@ void* Q2R_GetGameAPI(void* import, void*) { bool Q2R_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; - orig_export = (game_export_t*)mod_GetGameAPI(&qmm_import, nullptr); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; + orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); return !!orig_export; } diff --git a/src/game_q3a.cpp b/src/game_q3a.cpp index 93014e5..9f21e61 100644 --- a/src/game_q3a.cpp +++ b/src/game_q3a.cpp @@ -23,10 +23,10 @@ GEN_QMM_MSGS(Q3A); GEN_EXTS(Q3A); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -106,7 +106,7 @@ intptr_t Q3A_vmMain(intptr_t cmd, ...) { } -void Q3A_dllEntry(eng_syscall_t syscall) { +void Q3A_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Q3A_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -123,7 +123,7 @@ void Q3A_dllEntry(eng_syscall_t syscall) { bool Q3A_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } diff --git a/src/game_quake2.cpp b/src/game_quake2.cpp index 3500408..da5cf48 100644 --- a/src/game_quake2.cpp +++ b/src/game_quake2.cpp @@ -111,7 +111,7 @@ static qboolean QUAKE2_ClientConnect(edict_t* ent, char* userinfo) { else s_userinfo[clientnum] = userinfo; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; return vmMain(GAME_CLIENT_CONNECT, ent, userinfo); } @@ -127,7 +127,7 @@ static void QUAKE2_ClientUserinfoChanged(edict_t* ent, char* userinfo) { else s_userinfo[clientnum] = userinfo; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_CLIENT_USERINFO_CHANGED, ent, userinfo); } @@ -140,7 +140,7 @@ static void QUAKE2_SpawnEntities(char* mapname, char* entstring, char* spawnpoin s_entity_tokens = util_parse_entstring(entstring); s_tokencount = 0; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_SPAWN_ENTITIES, mapname, entstring, spawnpoint); } @@ -523,8 +523,8 @@ void* QUAKE2_GetGameAPI(void* import, void*) { bool QUAKE2_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; - orig_export = (game_export_t*)mod_GetGameAPI(&qmm_import, nullptr); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; + orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); return !!orig_export; } diff --git a/src/game_rtcwmp.cpp b/src/game_rtcwmp.cpp index fd87e3b..e2a28cc 100644 --- a/src/game_rtcwmp.cpp +++ b/src/game_rtcwmp.cpp @@ -23,10 +23,10 @@ GEN_QMM_MSGS(RTCWMP); GEN_EXTS(RTCWMP); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -101,7 +101,7 @@ intptr_t RTCWMP_vmMain(intptr_t cmd, ...) { } -void RTCWMP_dllEntry(eng_syscall_t syscall) { +void RTCWMP_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWMP_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -118,7 +118,7 @@ void RTCWMP_dllEntry(eng_syscall_t syscall) { bool RTCWMP_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } diff --git a/src/game_rtcwsp.cpp b/src/game_rtcwsp.cpp index 7c54b73..e774118 100644 --- a/src/game_rtcwsp.cpp +++ b/src/game_rtcwsp.cpp @@ -23,10 +23,10 @@ GEN_QMM_MSGS(RTCWSP); GEN_EXTS(RTCWSP); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -101,7 +101,7 @@ intptr_t RTCWSP_vmMain(intptr_t cmd, ...) { } -void RTCWSP_dllEntry(eng_syscall_t syscall) { +void RTCWSP_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("RTCWSP_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -118,7 +118,7 @@ void RTCWSP_dllEntry(eng_syscall_t syscall) { bool RTCWSP_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } diff --git a/src/game_sin.cpp b/src/game_sin.cpp index 96091e4..7cc0a98 100644 --- a/src/game_sin.cpp +++ b/src/game_sin.cpp @@ -157,7 +157,7 @@ static qboolean SIN_ClientConnect(edict_t* ent, const char* userinfo) { else s_userinfo[clientnum] = userinfo; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; return vmMain(GAME_CLIENT_CONNECT, ent, userinfo); } @@ -173,7 +173,7 @@ static void SIN_ClientUserinfoChanged(edict_t* ent, const char* userinfo) { else s_userinfo[clientnum] = userinfo; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_CLIENT_USERINFO_CHANGED, ent, userinfo); } @@ -186,7 +186,7 @@ static void SIN_SpawnEntities(const char* mapname, const char* entstring, const s_entity_tokens = util_parse_entstring(entstring); s_tokencount = 0; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_SPAWN_ENTITIES, mapname, entstring, spawnpoint); } @@ -640,8 +640,8 @@ void* SIN_GetGameAPI(void* import, void*) { bool SIN_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; - orig_export = (game_export_t*)mod_GetGameAPI(&qmm_import, nullptr); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; + orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); return !!orig_export; } diff --git a/src/game_sof2mp.cpp b/src/game_sof2mp.cpp index 4baff74..9715aff 100644 --- a/src/game_sof2mp.cpp +++ b/src/game_sof2mp.cpp @@ -24,10 +24,10 @@ GEN_QMM_MSGS(SOF2MP); GEN_EXTS(SOF2MP); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -143,7 +143,7 @@ intptr_t SOF2MP_vmMain(intptr_t cmd, ...) { } -void SOF2MP_dllEntry(eng_syscall_t syscall) { +void SOF2MP_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("SOF2MP_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -161,12 +161,12 @@ void SOF2MP_dllEntry(eng_syscall_t syscall) { // get mod's vmMain function pointer from mod.cpp::mod_load bool SOF2MP_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + 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.qvm.verify_data = false; + g_mod.vm.verify_data = false; return !!orig_vmMain; } diff --git a/src/game_sof2sp.cpp b/src/game_sof2sp.cpp index b0d9c13..0d26ce5 100644 --- a/src/game_sof2sp.cpp +++ b/src/game_sof2sp.cpp @@ -452,9 +452,9 @@ void* SOF2SP_GetGameAPI(void* apiversion, void* import) { bool SOF2SP_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; // api version gets passed before import pointer - orig_export = (game_export_t*)mod_GetGameAPI((void*)orig_apiversion, &qmm_import); + orig_export = (game_export_t*)pfnGGA((void*)orig_apiversion, &qmm_import); return !!orig_export; } diff --git a/src/game_stef2.cpp b/src/game_stef2.cpp index b76037f..20ab987 100644 --- a/src/game_stef2.cpp +++ b/src/game_stef2.cpp @@ -387,7 +387,7 @@ static void STEF2_SpawnEntities(const char* mapname, const char* entstring, int s_entity_tokens = util_parse_entstring(entstring); s_tokencount = 0; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_SPAWN_ENTITIES, mapname, entstring, levelTime); } @@ -968,8 +968,8 @@ void* STEF2_GetGameAPI(void* import, void*) { bool STEF2_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; - orig_export = (game_export_t*)mod_GetGameAPI(&qmm_import, nullptr); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; + orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); return !!orig_export; } diff --git a/src/game_stvoyhm.cpp b/src/game_stvoyhm.cpp index 69fd4e5..d9cd96a 100644 --- a/src/game_stvoyhm.cpp +++ b/src/game_stvoyhm.cpp @@ -23,10 +23,10 @@ GEN_QMM_MSGS(STVOYHM); GEN_EXTS(STVOYHM); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -107,7 +107,7 @@ intptr_t STVOYHM_vmMain(intptr_t cmd, ...) { } -void STVOYHM_dllEntry(eng_syscall_t syscall) { +void STVOYHM_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("STVOYHM_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -124,7 +124,7 @@ void STVOYHM_dllEntry(eng_syscall_t syscall) { bool STVOYHM_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } diff --git a/src/game_stvoysp.cpp b/src/game_stvoysp.cpp index f493040..c1f8236 100644 --- a/src/game_stvoysp.cpp +++ b/src/game_stvoysp.cpp @@ -86,7 +86,7 @@ static void STVOYSP_Init(const char* mapname, const char* spawntarget, int check s_entity_tokens = util_parse_entstring(entstring); s_tokencount = 0; } - cgame_is_QMM_vmMain_call = true; + cgame.is_from_QMM = true; vmMain(GAME_INIT, mapname, spawntarget, checkSum, entstring, levelTime, randomSeed, globalTime, eSavedGameJustLoaded, qbLoadTransition); } @@ -355,8 +355,8 @@ void* STVOYSP_GetGameAPI(void* import, void*) { bool STVOYSP_mod_load(void* entry) { - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)entry; - orig_export = (game_export_t*)mod_GetGameAPI(&qmm_import, nullptr); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)entry; + orig_export = (game_export_t*)pfnGGA(&qmm_import, nullptr); return !!orig_export; } diff --git a/src/game_wet.cpp b/src/game_wet.cpp index 8246c0c..a5a6990 100644 --- a/src/game_wet.cpp +++ b/src/game_wet.cpp @@ -23,10 +23,10 @@ GEN_QMM_MSGS(WET); GEN_EXTS(WET); // original syscall pointer that comes from the game engine -static eng_syscall_t orig_syscall = nullptr; +static eng_syscall orig_syscall = nullptr; // pointer to vmMain that comes from the mod -static mod_vmMain_t orig_vmMain = nullptr; +static mod_vmMain orig_vmMain = nullptr; // wrapper syscall function that calls actual engine func from orig_import // this is how QMM and plugins will call into the engine @@ -101,7 +101,7 @@ intptr_t WET_vmMain(intptr_t cmd, ...) { } -void WET_dllEntry(eng_syscall_t syscall) { +void WET_dllEntry(eng_syscall syscall) { LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("WET_dllEntry({}) called\n", (void*)syscall); // store original syscall from engine @@ -118,7 +118,7 @@ void WET_dllEntry(eng_syscall_t syscall) { bool WET_mod_load(void* entry) { - orig_vmMain = (mod_vmMain_t)entry; + orig_vmMain = (mod_vmMain)entry; return !!orig_vmMain; } diff --git a/src/log.cpp b/src/log.cpp index afd95cf..1a4abaf 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -53,7 +53,7 @@ void log_add_sink(T func, AixLog::Severity level = AixLog::Severity::notice) { std::string log_format(const AixLog::Metadata& metadata, const std::string& message, bool timestamp) { std::string output = fmt::format("({}) {}\n", metadata.tag.text, message); - if ((int)metadata.severity >= 5) + if ((int)metadata.severity >= QMM_LOG_WARNING) output = fmt::format("[{}] {}", AixLog::to_string(metadata.severity), output); if (timestamp && metadata.timestamp) output = fmt::format("{} {}", metadata.timestamp.to_string(), output); diff --git a/src/main.cpp b/src/main.cpp index 897d33c..720ce04 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,14 +24,13 @@ Created By: #include "util.h" #include "version.h" -game_info_t g_gameinfo; -bool g_shutdown = false; +gameinfo g_gameinfo; // cache some dynamic message values that get called a lot static intptr_t msg_G_PRINT, msg_GAME_INIT, msg_GAME_CONSOLE_COMMAND, msg_GAME_SHUTDOWN; static void s_main_detect_env(); -static void s_main_load_config(bool quiet = false); +static void s_main_load_config(); static void s_main_detect_game(std::string cfg_game, bool is_GetGameAPI_mode); static bool s_main_load_mod(std::string cfg_mod); static bool s_main_load_plugin(std::string plugin_path); @@ -84,38 +83,32 @@ static intptr_t s_main_route_syscall(intptr_t cmd, intptr_t* args); Since we don't care about the cgame system, QMM will forward the dllEntry call to the mod (with the real cgame syscall pointer), and then forward all the incoming cgame vmMain calls directly to the mod's vmMain function. - We do this with a few globals/statics. First, the static "cgame_passthrough_syscall" syscall pointer variable is used - to store the syscall pointer if dllEntry is called after QMM was already loaded from GetGameAPI. Then, dllEntry exits. + We do this with a few fields in the "cgame" struct. First, the "cgame.syscall" pointer variable is used to store the + syscall pointer if dllEntry is called after QMM was already loaded from GetGameAPI. Then, dllEntry exits. - Next, the global "cgame_is_QMM_vmMain_call" bool is used to flag incoming calls to vmMain as coming from a game-specific + Next, the "cgame.is_from_QMM" bool is used to flag incoming calls to vmMain as coming from a game-specific GetGameAPI vmMain wrapper struct (i.e. qmm_export) meaning the call actually came from the game system (as opposed to cgame). This flag is set in the GEN_EXPORT macro and all of the custom static polyfill functions that route to vmMain. It is set back to false immediately after checking and handling passthrough calls. - Next, when the GAME_INIT event comes through, and we load the actual mod DLL, we also check to see if - "cgame_passthrough_syscall" is set. If it is, we look for "dllEntry" in the DLL, and pass cgame_passthrough_syscall to it. - Next, we look for "vmMain" in the DLL and then store it in the static "cgame_passthrough_mod_vmMain" pointer. + Next, when the GAME_INIT event comes through, and we load the actual mod DLL, we also check to see if "cgame.syscall" + is set. If it is, we look for "dllEntry" in the DLL, and pass "cgame.syscall" to it. Next, we look for "vmMain" in + the DLL and then store it in the "cgame.vmMain" pointer. - Whenever control enters vmMain and "cgame_is_QMM_vmMain_call" is false (meaning it was called directly by the engine for - the cgame system), it routes the call to the mod's vmMain stored in "cgame_passthrough_mod_vmMain". + Whenever control enters vmMain and "cgame.is_from_QMM" is false (meaning it was called directly by the engine + for the cgame system), it routes the call to the mod's vmMain stored in "cgame.vmMain". The final piece is that single player games shutdown and init the DLL a lot, particularly at every new level or - between-level cutscene. When QMM detects that it is being shutdown and "cgame_passthrough_syscall" is set, it no longer - unloads the mod DLL and sets a static "cgame_passthrough_shutdown" bool to true. Then, when a vmMain call is being - handled as a passthrough, and "cgame_passthrough_shutdown" is true, it will then unload the mod DLL. This allows the - cgame system to shutdown properly. + between-level cutscene. When QMM detects that it is being shutdown and "cgame.syscall" is set, it no longer unloads + the mod DLL and sets "cgame.shutdown" bool to true. Then, when a vmMain call is being handled as a passthrough, and + "cgame.shutdown" is true, it will then unload the mod DLL. This allows the cgame system to shutdown properly. */ -// store syscall pointer if we need to pass it through to the mod's dllEntry function for games with -// combined game+cgame (singleplayer) -static eng_syscall_t cgame_passthrough_syscall = nullptr; -// flag that is set by GEN_EXPORT macro before calling into vmMain. used to tell if this is a call that -// should be directly routed to the mod or not in some single player games that have game & cgame in the -// same DLL -bool cgame_is_QMM_vmMain_call = false; -// store mod's vmMain function for cgame passthrough -static mod_vmMain_t cgame_passthrough_mod_vmMain = nullptr; -// GAME_SHUTDOWN has been called, but mod DLL was kept loaded so cgame shutdown can run -static bool cgame_passthrough_shutdown = false; +cgameinfo cgame = { + nullptr, // syscall + nullptr, // vmMain + false, // is_from_QMM + false, // shutdown +}; /* Entry point: engine->qmm @@ -124,13 +117,13 @@ static bool cgame_passthrough_shutdown = false; do is store the syscall, load the config file, and attempt to figure out what game engine we are in. This is either determined by the config file, or by getting the filename of the QMM DLL itself. */ -C_DLLEXPORT void dllEntry(eng_syscall_t syscall) { +C_DLLEXPORT void dllEntry(eng_syscall syscall) { // cgame passthrough hack: // QMM is already loaded, so this is a cgame passthrough situation. since the mod DLL isn't loaded yet, we can // just store the syscall pointer and pass it to the mod once it's loaded in vmMain(GAME_INIT) if (g_gameinfo.game) { - cgame_passthrough_syscall = syscall; - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QMM passthrough_syscall = {}\n", (void*)cgame_passthrough_syscall); + cgame.syscall = syscall; + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("QMM passthrough_syscall = {}\n", (void*)cgame.syscall); return; } @@ -141,7 +134,7 @@ C_DLLEXPORT void dllEntry(eng_syscall_t syscall) { LOG(QMM_LOG_NOTICE, "QMM") << "QMM v" QMM_VERSION " (" QMM_OS " " QMM_ARCH ") (dllEntry) loaded!\n"; 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.moddir); + LOG(QMM_LOG_INFO, "QMM") << fmt::format("Mod directory (?): \"{}\"\n", g_gameinfo.mod_dir); // ??? if (!syscall) { @@ -237,7 +230,7 @@ C_DLLEXPORT void* GetGameAPI(void* import, void* extra) { LOG(QMM_LOG_NOTICE, "QMM") << "QMM v" QMM_VERSION " (" QMM_OS " " QMM_ARCH ") (GetGameAPI) loaded!\n"; 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.moddir); + LOG(QMM_LOG_INFO, "QMM") << fmt::format("Mod directory (?): \"{}\"\n", g_gameinfo.mod_dir); // ??? // return nullptr to error out now, Init() will never be called @@ -303,22 +296,22 @@ C_DLLEXPORT intptr_t vmMain(intptr_t cmd, ...) { QMM_GET_VMMAIN_ARGS(); // if this is a call from cgame and we need to pass this call onto the mod - if (cgame_passthrough_syscall && !cgame_is_QMM_vmMain_call) { + if (cgame.syscall && !cgame.is_from_QMM) { // cancel if cgame portion of mod isn't actually loaded yet - if (!cgame_passthrough_mod_vmMain) + if (!cgame.vmMain) return 0; #ifdef _DEBUG LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Passthrough vmMain({}) called\n", cmd); #endif - intptr_t ret = cgame_passthrough_mod_vmMain(cmd, QMM_PUT_VMMAIN_ARGS()); + intptr_t ret = cgame.vmMain(cmd, QMM_PUT_VMMAIN_ARGS()); #ifdef _DEBUG LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Passthrough vmMain({}) returning {}\n", cmd, ret); #endif - if (cgame_passthrough_shutdown) { + if (cgame.shutdown) { // unload mod (dlclose) LOG(QMM_LOG_NOTICE, "QMM") << "Shutting down mod\n"; mod_unload(g_mod); @@ -328,12 +321,12 @@ C_DLLEXPORT intptr_t vmMain(intptr_t cmd, ...) { } // clear passthrough flag - cgame_is_QMM_vmMain_call = false; + cgame.is_from_QMM = false; // couldn't load engine info, so we will just call syscall(G_ERROR) to exit if (!g_gameinfo.game) { - if (!g_shutdown) { - g_shutdown = true; + if (!g_gameinfo.isshutdown) { + g_gameinfo.isshutdown = true; ENG_SYSCALL(QMM_FAIL_G_ERROR, "\n\n=========\nFatal QMM Error:\nQMM was unable to determine the game engine.\nPlease set the \"game\" option in qmm2.json.\nRefer to the documentation for more information.\n=========\n"); } return 0; @@ -358,13 +351,13 @@ C_DLLEXPORT intptr_t vmMain(intptr_t cmd, ...) { char moddir[256]; ENG_SYSCALL(QMM_ENG_MSG[QMM_G_CVAR_VARIABLE_STRING_BUFFER], "fs_game", moddir, sizeof(moddir)); moddir[sizeof(moddir) - 1] = '\0'; - g_gameinfo.moddir = moddir; + g_gameinfo.mod_dir = moddir; // the default mod (including all singleplayer games) returns "" for the fs_game, so grab the default mod dir from game info instead - if (g_gameinfo.moddir.empty()) - g_gameinfo.moddir = g_gameinfo.game->moddir; + if (g_gameinfo.mod_dir.empty()) + g_gameinfo.mod_dir = g_gameinfo.game->moddir; LOG(QMM_LOG_INFO, "QMM") << fmt::format("Game: {}/\"{}\" (Source: {})\n", g_gameinfo.game->gamename_short, g_gameinfo.game->gamename_long, g_gameinfo.isautodetected ? "Auto-detected" : "Config file"); - LOG(QMM_LOG_INFO, "QMM") << fmt::format("ModDir: {}\n", g_gameinfo.moddir); + LOG(QMM_LOG_INFO, "QMM") << fmt::format("ModDir: {}\n", g_gameinfo.mod_dir); LOG(QMM_LOG_INFO, "QMM") << fmt::format("Config file: \"{}\" {}\n", g_gameinfo.cfg_path, g_cfg.is_discarded() ? "(error)" : ""); LOG(QMM_LOG_INFO, "QMM") << "Built: " QMM_COMPILE " by " QMM_BUILDER "\n"; @@ -384,14 +377,14 @@ C_DLLEXPORT intptr_t vmMain(intptr_t cmd, ...) { // cgame passthrough hack: // JASP (and others?) calls into the cgame syscall before a cgame vmMain GAME_INIT call is made // so if we have a passthrough situation, init the mod's cgame functions now - if (cgame_passthrough_syscall) { + if (cgame.syscall) { // pass original cgame syscall to dllEntry in mod - mod_dllEntry_t cgame_passthrough_mod_dllEntry = (mod_dllEntry_t)dlsym(g_mod.dll, "dllEntry"); - cgame_passthrough_mod_dllEntry(cgame_passthrough_syscall); - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Passing syscall passthrough to mod. dllEntry = {}\n", (void*)cgame_passthrough_mod_dllEntry); + mod_dllEntry pfndllEntry = (mod_dllEntry)dlsym(g_mod.dll, "dllEntry"); + pfndllEntry(cgame.syscall); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Passing syscall passthrough to mod. dllEntry = {}\n", (void*)pfndllEntry); - cgame_passthrough_mod_vmMain = (mod_vmMain_t)dlsym(g_mod.dll, "vmMain"); - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Passthrough vmMain = {}\n", (void*)cgame_passthrough_mod_vmMain); + cgame.vmMain = (mod_vmMain)dlsym(g_mod.dll, "vmMain"); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Passthrough vmMain = {}\n", (void*)cgame.vmMain); } // load plugins @@ -445,8 +438,8 @@ C_DLLEXPORT intptr_t vmMain(intptr_t cmd, ...) { // cgame passthrough hack: // hack to keep single player games shutting down correctly between levels/cutscenes/etc - if (cgame_passthrough_syscall) { - cgame_passthrough_shutdown = true; + if (cgame.syscall) { + cgame.shutdown = true; LOG(QMM_LOG_NOTICE, "QMM") << "Delaying shutting down mod so cgame shutdown can run\n"; } else { @@ -457,7 +450,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_t& p : g_plugins) { + for (plugin& p : g_plugins) { plugin_unload(p); } g_plugins.clear(); @@ -531,39 +524,36 @@ static void s_main_detect_env() { // likely that this is a singleplayer game, so just set the temporary moddir to ".". // this doesn't have to be exact, since it will only be used only for config loading. if (str_striequal(g_gameinfo.qmm_dir, g_gameinfo.exe_dir)) { - g_gameinfo.moddir = "."; + g_gameinfo.mod_dir = "."; } else { - g_gameinfo.moddir = path_basename(g_gameinfo.qmm_dir); + g_gameinfo.mod_dir = path_basename(g_gameinfo.qmm_dir); } } // general code to load config file. called from dllEntry() and GetGameAPI() -static void s_main_load_config(bool quiet) { +static void s_main_load_config() { // load config file, try the following locations in order: // "/qmm2.json" // "//qmm2.json" // ".//qmm2.json" std::string try_paths[] = { fmt::format("{}/qmm2.json", g_gameinfo.qmm_dir), - fmt::format("{}/{}/qmm2.json", g_gameinfo.exe_dir, g_gameinfo.moddir), - fmt::format("./{}/qmm2.json", g_gameinfo.moddir) + fmt::format("{}/{}/qmm2.json", g_gameinfo.exe_dir, g_gameinfo.mod_dir), + fmt::format("./{}/qmm2.json", g_gameinfo.mod_dir) }; for (std::string& try_path : try_paths) { g_cfg = cfg_load(try_path); if (!g_cfg.empty()) { g_gameinfo.cfg_path = try_path; - if (!quiet) - LOG(QMM_LOG_NOTICE, "QMM") << fmt::format("Config file found! Path: \"{}\"\n", g_gameinfo.cfg_path); - break; + LOG(QMM_LOG_NOTICE, "QMM") << fmt::format("Config file found! Path: \"{}\"\n", g_gameinfo.cfg_path); + return; } } - if (g_cfg.empty() || g_cfg.is_discarded()) { - // a default constructed json object is a blank {}, so in case of load failure, we can still try to read from it and assume defaults - if (!quiet) - LOG(QMM_LOG_WARNING, "QMM") << "Unable to load config file, all settings will use default values\n"; - } + + // a default constructed json object is a blank {}, so in case of load failure, we can still try to read from it and assume defaults + LOG(QMM_LOG_WARNING, "QMM") << "Unable to load config file, all settings will use default values\n"; } @@ -571,7 +561,7 @@ static void s_main_load_config(bool quiet) { static void s_main_detect_game(std::string cfg_game, bool is_GetGameAPI_mode) { // find what game we are loaded in for (int i = 0; g_supportedgames[i].dllname; i++) { - supportedgame_t& game = g_supportedgames[i]; + supportedgame& game = g_supportedgames[i]; // only check games with apientry based on GetGameAPI_mode if (is_GetGameAPI_mode != !!game.pfnGetGameAPI) continue; @@ -586,9 +576,8 @@ static void s_main_detect_game(std::string cfg_game, bool is_GetGameAPI_mode) { // otherwise, if auto, we need to check matching dll names, with optional exe hint if (str_striequal(cfg_game, "auto")) { // dll name matches - std::string full_dll_name = fmt::format("{}.{}", game.dllname, EXT_DLL); - if (str_striequal(g_gameinfo.qmm_file, full_dll_name)) { - LOG(QMM_LOG_INFO, "QMM") << fmt::format("Found game match for dll name \"{}\" - {}\n", full_dll_name, game.gamename_short); + if (str_striequal(g_gameinfo.qmm_file, game.dllname)) { + LOG(QMM_LOG_INFO, "QMM") << fmt::format("Found game match for dll name \"{}\" - {}\n", game.dllname, game.gamename_short); // if no hint array exists, assume we match if (!game.exe_hints.size()) { LOG(QMM_LOG_NOTICE, "QMM") << fmt::format("No exe hint for game, assuming match\n"); @@ -629,10 +618,10 @@ static bool s_main_load_mod(std::string cfg_mod) { else if (str_striequal(cfg_mod, "auto")) { std::string try_paths[] = { g_gameinfo.game->qvmname ? g_gameinfo.game->qvmname : "", // (only if game engine supports it) - fmt::format("{}/qmm_{}.{}", g_gameinfo.qmm_dir, g_gameinfo.game->dllname, EXT_DLL), - fmt::format("{}/{}/qmm_{}.{}", g_gameinfo.exe_dir, g_gameinfo.moddir, g_gameinfo.game->dllname, EXT_DLL), - fmt::format("{}/{}/{}.{}", g_gameinfo.exe_dir, g_gameinfo.moddir, g_gameinfo.game->dllname, EXT_DLL), - fmt::format("./{}/qmm_{}.{}", g_gameinfo.moddir, g_gameinfo.game->dllname, EXT_DLL) + fmt::format("{}/qmm_{}", g_gameinfo.qmm_dir, g_gameinfo.game->dllname), + fmt::format("{}/{}/qmm_{}", g_gameinfo.exe_dir, g_gameinfo.mod_dir, g_gameinfo.game->dllname), + fmt::format("{}/{}/{}", g_gameinfo.exe_dir, g_gameinfo.mod_dir, g_gameinfo.game->dllname), + fmt::format("./{}/qmm_{}", g_gameinfo.mod_dir, g_gameinfo.game->dllname) }; // try paths for (std::string& try_path : try_paths) { @@ -652,8 +641,8 @@ static bool s_main_load_mod(std::string cfg_mod) { std::string try_paths[] = { cfg_mod, fmt::format("{}/{}", g_gameinfo.qmm_dir, cfg_mod), - fmt::format("{}/{}/{}", g_gameinfo.exe_dir, g_gameinfo.moddir, cfg_mod), - fmt::format("./{}/{}", g_gameinfo.moddir, cfg_mod) + fmt::format("{}/{}/{}", g_gameinfo.exe_dir, g_gameinfo.mod_dir, cfg_mod), + fmt::format("./{}/{}", g_gameinfo.mod_dir, cfg_mod) }; // try paths for (std::string& try_path : try_paths) { @@ -671,7 +660,7 @@ static bool s_main_load_mod(std::string cfg_mod) { // general code to find a plugin file to load static bool s_main_load_plugin(std::string plugin_path) { - plugin_t p; + 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 @@ -687,8 +676,8 @@ static bool s_main_load_plugin(std::string plugin_path) { // ".//" std::string try_paths[] = { fmt::format("{}/{}", g_gameinfo.qmm_dir, plugin_path), - fmt::format("{}/{}/{}", g_gameinfo.exe_dir, g_gameinfo.moddir, plugin_path), - fmt::format("./{}/{}", g_gameinfo.moddir, plugin_path) + fmt::format("{}/{}/{}", g_gameinfo.exe_dir, g_gameinfo.mod_dir, plugin_path), + fmt::format("./{}/{}", g_gameinfo.mod_dir, plugin_path) }; for (std::string& try_path : try_paths) { // plugin_load returns 0 if no plugin file was found, 1 if success, and -1 if file was found but failure @@ -717,7 +706,7 @@ static void s_main_handle_command_qmm(intptr_t arg_start) { if (str_striequal("status", arg1) || str_striequal("info", arg1)) { ENG_SYSCALL(msg_G_PRINT, "(QMM) QMM v" QMM_VERSION " (" QMM_OS " " QMM_ARCH ") loaded\n"); ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) Game: {}/\"{}\" (Source: {})\n", g_gameinfo.game->gamename_short, g_gameinfo.game->gamename_long, g_gameinfo.isautodetected ? "Auto-detected" : "Config file").c_str()); - ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) ModDir: {}\n", g_gameinfo.moddir).c_str()); + ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) ModDir: {}\n", g_gameinfo.mod_dir).c_str()); ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) Config file: \"{}\" {}\n", g_gameinfo.cfg_path, g_cfg.is_discarded() ? " (error)" : "").c_str()); ENG_SYSCALL(msg_G_PRINT, "(QMM) Built: " QMM_COMPILE " by " QMM_BUILDER "\n"); ENG_SYSCALL(msg_G_PRINT, "(QMM) URL: " QMM_URL "\n"); @@ -725,21 +714,21 @@ static void s_main_handle_command_qmm(intptr_t arg_start) { ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) Plugins loaded: {}\n", g_plugins.size()).c_str()); ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) Loaded mod file: {}\n", g_mod.path).c_str()); if (g_mod.vmbase) { - ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM file size : {}\n", g_mod.qvm.filesize).c_str()); - ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM memory base : {}\n", (void*)g_mod.qvm.memory).c_str()); - ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM memory size : {}\n", g_mod.qvm.memorysize).c_str()); - ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM instr count : {}\n", g_mod.qvm.instructioncount).c_str()); - ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM codeseg size : {}\n", g_mod.qvm.codeseglen).c_str()); - ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM dataseg size : {}\n", g_mod.qvm.dataseglen).c_str()); - ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM stack size : {}\n", g_mod.qvm.stacksize).c_str()); - ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM data validation: {}\n", g_mod.qvm.verify_data ? "on" : "off").c_str()); + ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM file size : {}\n", g_mod.vm.filesize).c_str()); + ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM memory base : {}\n", (void*)g_mod.vm.memory).c_str()); + ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM memory size : {}\n", g_mod.vm.memorysize).c_str()); + ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM instr count : {}\n", g_mod.vm.instructioncount).c_str()); + ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM codeseg size : {}\n", g_mod.vm.codeseglen).c_str()); + ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM dataseg size : {}\n", g_mod.vm.dataseglen).c_str()); + ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM stack size : {}\n", g_mod.vm.stacksize).c_str()); + ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) QVM data validation: {}\n", g_mod.vm.verify_data ? "on" : "off").c_str()); } } else if (str_striequal("list", arg1)) { ENG_SYSCALL(msg_G_PRINT, "(QMM) id - plugin [version]\n"); ENG_SYSCALL(msg_G_PRINT, "(QMM) ---------------------\n"); int num = 1; - for (plugin_t& p : g_plugins) { + for (plugin& p : g_plugins) { ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) {:>2} - {} [{}]\n", num, p.plugininfo->name, p.plugininfo->version).c_str()); num++; } @@ -751,7 +740,7 @@ static void s_main_handle_command_qmm(intptr_t arg_start) { } size_t pid = (size_t)atoi(arg2); if (pid > 0 && pid <= g_plugins.size()) { - plugin_t& p = g_plugins[pid - 1]; + plugin& p = g_plugins[pid - 1]; ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) Plugin info for #{}:\n", arg2).c_str()); ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) Name: {}\n", p.plugininfo->name).c_str()); ENG_SYSCALL(msg_G_PRINT, fmt::format("(QMM) Version: {}\n", p.plugininfo->version).c_str()); @@ -793,7 +782,7 @@ static intptr_t s_main_route_vmmain(intptr_t cmd, intptr_t* args) { #endif // store max result - pluginres_t max_result = QMM_UNUSED; + plugin_res max_result = QMM_UNUSED; // return values from a plugin call intptr_t plugin_ret = 0; // return value from mod call @@ -802,7 +791,7 @@ static intptr_t s_main_route_vmmain(intptr_t cmd, intptr_t* args) { intptr_t final_ret = 0; // begin passing calls to plugins' QMM_vmMain functions - for (plugin_t& p : g_plugins) { + for (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; @@ -859,7 +848,7 @@ static intptr_t s_main_route_vmmain(intptr_t cmd, intptr_t* args) { final_ret = mod_ret; // pass calls to plugins' QMM_vmMain_Post functions (QMM_OVERRIDE or QMM_SUPERCEDE can still change final_ret) - for (plugin_t& p : g_plugins) { + for (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; @@ -895,7 +884,7 @@ static intptr_t s_main_route_syscall(intptr_t cmd, intptr_t* args) { #endif // store max result - pluginres_t max_result = QMM_UNUSED; + plugin_res max_result = QMM_UNUSED; // return values from a plugin call intptr_t plugin_ret = 0; // return value from engine call @@ -904,7 +893,7 @@ static intptr_t s_main_route_syscall(intptr_t cmd, intptr_t* args) { intptr_t final_ret = 0; // begin passing calls to plugins' QMM_syscall functions - for (plugin_t& p : g_plugins) { + for (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; @@ -961,7 +950,7 @@ static intptr_t s_main_route_syscall(intptr_t cmd, intptr_t* args) { final_ret = eng_ret; // pass calls to plugins' QMM_syscall_Post functions (ignore return values and results) - for (plugin_t& p : g_plugins) { + for (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; @@ -1013,8 +1002,8 @@ C_DLLEXPORT void* GetCGameAPI(void* import) { if (!g_mod.dll) return nullptr; LOG(QMM_LOG_DEBUG, "QMM") << "GetCGameAPI() called! Passing on call to mod DLL.\n"; - mod_GetGameAPI_t mod_GetCGameAPI = (mod_GetGameAPI_t)dlsym(g_mod.dll, "GetCGameAPI"); - return mod_GetCGameAPI ? mod_GetCGameAPI(import, nullptr) : nullptr; + mod_GetGameAPI pfnGCGA = (mod_GetGameAPI)dlsym(g_mod.dll, "GetCGameAPI"); + return pfnGCGA ? pfnGCGA(import, nullptr) : nullptr; } // client-side-only load. just get file info and slap "qmm_" in front of the qmm filename @@ -1025,10 +1014,10 @@ C_DLLEXPORT void* GetCGameAPI(void* import) { if (!dll) return nullptr; - mod_GetGameAPI_t mod_GetCGameAPI = (mod_GetGameAPI_t)dlsym(dll, "GetCGameAPI"); + mod_GetGameAPI pfnGCGA = (mod_GetGameAPI)dlsym(dll, "GetCGameAPI"); // return CGame export from mod DLL // note we do not unload the DLL - return mod_GetCGameAPI ? mod_GetCGameAPI(import, nullptr) : nullptr; + return pfnGCGA ? pfnGCGA(import, nullptr) : nullptr; } #endif // _WIN64 diff --git a/src/mod.cpp b/src/mod.cpp index 4ce05ce..bf06717 100644 --- a/src/mod.cpp +++ b/src/mod.cpp @@ -24,18 +24,18 @@ Created By: #include "plugin.h" #include "util.h" -mod_t g_mod; +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_t& mod); -static bool s_mod_load_vmmain(mod_t& mod); -static bool s_mod_load_getgameapi(mod_t& mod); +static bool s_mod_load_qvm(mod& mod); +static bool s_mod_load_vmmain(mod& mod); +static bool s_mod_load_getgameapi(mod& mod); -bool mod_load(mod_t& mod, std::string file) { - // if this mod_t somehow already has a dll or qvm pointer, wipe it first - if (mod.dll || mod.qvm.memory) +bool mod_load(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); mod.path = file; @@ -47,7 +47,7 @@ bool mod_load(mod_t& mod, std::string file) { return s_mod_load_qvm(mod); // if DLL - else if (str_striequal(ext, EXT_DLL)) { + else { // load DLL if (!(mod.dll = dlopen(file.c_str(), RTLD_NOW))) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): DLL load failed: {}\n", file, dlerror()); @@ -73,23 +73,23 @@ bool mod_load(mod_t& mod, std::string file) { } -void mod_unload(mod_t& mod) { +void mod_unload(mod& mod) { // call the game-specific mod unload callback if (g_gameinfo.game->pfnModUnload) g_gameinfo.game->pfnModUnload(); - qvm_unload(&mod.qvm); + qvm_unload(&mod.vm); if (mod.dll) dlclose(mod.dll); - mod = mod_t(); + mod = ::mod(); } // entry point into QVM mods. stored in mod_t->pfnvmMain for QVM mods static intptr_t s_mod_qvm_vmmain(intptr_t cmd, ...) { // if qvm isn't loaded, we need to error - if (!g_mod.qvm.memory) { - if (!g_shutdown) { - g_shutdown = true; + if (!g_mod.vm.memory) { + if (!g_gameinfo.isshutdown) { + g_gameinfo.isshutdown = true; LOG(QMM_LOG_FATAL, "QMM") << fmt::format("s_mod_vmmain({}): QVM unloaded during previous execution due to a run-time error\n", g_gameinfo.game->mod_msg_names(cmd)); ENG_SYSCALL(QMM_ENG_MSG[QMM_G_ERROR], "\n\n=========\nFatal QMM Error:\nThe QVM was unloaded during previous execution due to a run-time error.\n=========\n"); } @@ -105,7 +105,7 @@ static intptr_t s_mod_qvm_vmmain(intptr_t cmd, ...) { } // pass array and size to qvm - return qvm_exec(&g_mod.qvm, QVM_MAX_VMMAIN_ARGS + 1, qvmargs); + return qvm_exec(&g_mod.vm, QVM_MAX_VMMAIN_ARGS + 1, qvmargs); } @@ -113,7 +113,7 @@ static intptr_t s_mod_qvm_vmmain(intptr_t cmd, ...) { 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_t* p = g_registered_qvm_funcs[cmd]; + 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) @@ -125,8 +125,8 @@ 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->pfnqvmsyscall) { - if (!g_shutdown) { - g_shutdown = true; + if (!g_gameinfo.isshutdown) { + g_gameinfo.isshutdown = true; LOG(QMM_LOG_FATAL, "QMM") << fmt::format("s_mod_qvm_syscall({}): No QVM syscall handler found\n", g_gameinfo.game->eng_msg_names(cmd)); ENG_SYSCALL(QMM_ENG_MSG[QMM_G_ERROR], "\n\n=========\nFatal QMM Error:\nNo QVM syscall handler found.\n=========\n"); } @@ -139,7 +139,7 @@ static int s_mod_qvm_syscall(uint8_t* membase, int cmd, int* args) { // load a QVM mod -static bool s_mod_load_qvm(mod_t& mod) { +static bool s_mod_load_qvm(mod& mod) { int fpk3 = 0; intptr_t filelen; std::vector filemem; @@ -163,13 +163,13 @@ static bool s_mod_load_qvm(mod_t& mod) { verify_data = cfg_get_bool(g_cfg, "qvmverifydata", true); // attempt to load mod - loaded = qvm_load(&mod.qvm, filemem.data(), filemem.size(), s_mod_qvm_syscall, verify_data, nullptr); + loaded = qvm_load(&mod.vm, filemem.data(), filemem.size(), s_mod_qvm_syscall, verify_data, nullptr); if (!loaded) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): QVM load failed\n", mod.path); goto fail; } - mod.vmbase = (intptr_t)mod.qvm.datasegment; + mod.vmbase = (intptr_t)mod.vm.datasegment; // pass the qvm vmMain function pointer to the game-specific mod load handler if (!g_gameinfo.game->pfnModLoad((void*)s_mod_qvm_vmmain)) { @@ -186,11 +186,11 @@ static bool s_mod_load_qvm(mod_t& mod) { // load a GetGameAPI DLL mod -static bool s_mod_load_getgameapi(mod_t& mod) { +static bool s_mod_load_getgameapi(mod& mod) { // look for GetGameAPI function - mod_GetGameAPI_t mod_GetGameAPI = (mod_GetGameAPI_t)dlsym(mod.dll, "GetGameAPI"); + mod_GetGameAPI pfnGGA = (mod_GetGameAPI)dlsym(mod.dll, "GetGameAPI"); - if (!mod_GetGameAPI) { + if (!pfnGGA) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Unable to find \"GetGameAPI\" function\n", mod.path); goto fail; } @@ -198,7 +198,7 @@ static bool s_mod_load_getgameapi(mod_t& mod) { mod.vmbase = 0; // pass the GetGameAPI function pointer to the game-specific mod load handler - if (!g_gameinfo.game->pfnModLoad((void*)mod_GetGameAPI)) { + if (!g_gameinfo.game->pfnModLoad((void*)pfnGGA)) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): \"GetGameAPI\" function failed\n", mod.path); goto fail; } @@ -212,29 +212,29 @@ static bool s_mod_load_getgameapi(mod_t& mod) { // load a vmMain DLL mod -static bool s_mod_load_vmmain(mod_t& mod) { - mod_dllEntry_t mod_dllEntry = nullptr; - mod_vmMain_t mod_vmMain = nullptr; +static bool s_mod_load_vmmain(mod& mod) { + mod_dllEntry pfndllEntry = nullptr; + mod_vmMain pfnvmMain = nullptr; // look for dllEntry function - if (!(mod_dllEntry = (mod_dllEntry_t)dlsym(mod.dll, "dllEntry"))) { + if (!(pfndllEntry = (mod_dllEntry)dlsym(mod.dll, "dllEntry"))) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Unable to find \"dllEntry\" function\n", mod.path); goto fail; } // look for vmMain function - if (!(mod_vmMain = (mod_vmMain_t)dlsym(mod.dll, "vmMain"))) { + if (!(pfnvmMain = (mod_vmMain)dlsym(mod.dll, "vmMain"))) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Unable to find \"vmMain\" function\n", mod.path); goto fail; } // pass qmm_syscall to mod's dllEntry function - mod_dllEntry(qmm_syscall); + pfndllEntry(qmm_syscall); mod.vmbase = 0; // pass the vmMain function pointer to the game-specific mod load handler - if (!g_gameinfo.game->pfnModLoad((void*)mod_vmMain)) { + if (!g_gameinfo.game->pfnModLoad((void*)pfnvmMain)) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("mod_load(\"{}\"): Mod load failed?\n", mod.path); goto fail; } diff --git a/src/plugin.cpp b/src/plugin.cpp index b8615a8..f7b4c86 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -29,30 +29,30 @@ Created By: constexpr int NUM_PLUGIN_STR_BUFFERS = 16; // must be power of 2 constexpr int NUM_PLUGIN_STR_BUFFER_MASK = NUM_PLUGIN_STR_BUFFERS - 1; -static void s_plugin_helper_WriteQMMLog(plid_t plid, const char* text, int severity); -static char* s_plugin_helper_VarArgs(plid_t plid [[maybe_unused]], const char* format, ...); -static int s_plugin_helper_IsQVM(plid_t plid [[maybe_unused]] ); -static const char* s_plugin_helper_EngMsgName(plid_t plid [[maybe_unused]], intptr_t msg); -static const char* s_plugin_helper_ModMsgName(plid_t plid [[maybe_unused]], intptr_t msg); -static intptr_t s_plugin_helper_GetIntCvar(plid_t plid [[maybe_unused]], const char* cvar); -static const char* s_plugin_helper_GetStrCvar(plid_t plid [[maybe_unused]], const char* cvar); -static const char* s_plugin_helper_GetGameEngine(plid_t plid [[maybe_unused]] ); -static void s_plugin_helper_Argv(plid_t plid [[maybe_unused]], intptr_t argn, char* buf, intptr_t buflen); -static const char* s_plugin_helper_InfoValueForKey(plid_t plid [[maybe_unused]], const char* userinfo, const char* key); -static const char* s_plugin_helper_ConfigGetStr(plid_t plid [[maybe_unused]], const char* key); -static int s_plugin_helper_ConfigGetInt(plid_t plid [[maybe_unused]], const char* key); -static int s_plugin_helper_ConfigGetBool(plid_t plid [[maybe_unused]], const char* key); -static const char** s_plugin_helper_ConfigGetArrayStr(plid_t plid [[maybe_unused]], const char* key); -static int* s_plugin_helper_ConfigGetArrayInt(plid_t plid [[maybe_unused]], const char* key); -static void s_plugin_helper_GetConfigString(plid_t plid [[maybe_unused]], intptr_t index, char* buf, intptr_t buflen); -static int s_plugin_helper_PluginBroadcast(plid_t plid, const char* message, void* buf, intptr_t buflen); -static int s_plugin_helper_PluginSend(plid_t plid, plid_t to_plid, const char* message, void* buf, intptr_t buflen); -static int s_plugin_helper_QVMRegisterFunc(plid_t plid); -static int s_plugin_helper_QVMExecFunc(plid_t plid [[maybe_unused]], int funcid, int argc, int* argv); -static const char* s_plugin_helper_Argv2(plid_t plid [[maybe_unused]], intptr_t argn); -static const char* s_plugin_helper_GetConfigString2(plid_t plid [[maybe_unused]], intptr_t index); - -static pluginfuncs_t s_pluginfuncs = { +static void s_plugin_helper_WriteQMMLog(plugin_id plid, const char* text, int severity); +static char* s_plugin_helper_VarArgs(plugin_id plid [[maybe_unused]], const char* format, ...); +static int s_plugin_helper_IsQVM(plugin_id plid [[maybe_unused]] ); +static const char* s_plugin_helper_EngMsgName(plugin_id plid [[maybe_unused]], intptr_t msg); +static const char* s_plugin_helper_ModMsgName(plugin_id plid [[maybe_unused]], intptr_t msg); +static intptr_t s_plugin_helper_GetIntCvar(plugin_id plid [[maybe_unused]], const char* cvar); +static const char* s_plugin_helper_GetStrCvar(plugin_id plid [[maybe_unused]], const char* cvar); +static const char* s_plugin_helper_GetGameEngine(plugin_id plid [[maybe_unused]] ); +static void s_plugin_helper_Argv(plugin_id plid [[maybe_unused]], intptr_t argn, char* buf, intptr_t buflen); +static const char* s_plugin_helper_InfoValueForKey(plugin_id plid [[maybe_unused]], const char* userinfo, const char* key); +static const char* s_plugin_helper_ConfigGetStr(plugin_id plid [[maybe_unused]], const char* key); +static int s_plugin_helper_ConfigGetInt(plugin_id plid [[maybe_unused]], const char* key); +static int s_plugin_helper_ConfigGetBool(plugin_id plid [[maybe_unused]], const char* key); +static const char** s_plugin_helper_ConfigGetArrayStr(plugin_id plid [[maybe_unused]], const char* key); +static int* s_plugin_helper_ConfigGetArrayInt(plugin_id plid [[maybe_unused]], const char* key); +static void s_plugin_helper_GetConfigString(plugin_id plid [[maybe_unused]], intptr_t index, char* buf, intptr_t buflen); +static int s_plugin_helper_PluginBroadcast(plugin_id plid, const char* message, void* buf, intptr_t buflen); +static int s_plugin_helper_PluginSend(plugin_id plid, plugin_id to_plid, const char* message, void* buf, intptr_t buflen); +static int s_plugin_helper_QVMRegisterFunc(plugin_id plid); +static int s_plugin_helper_QVMExecFunc(plugin_id plid [[maybe_unused]], int funcid, int argc, int* argv); +static const char* s_plugin_helper_Argv2(plugin_id plid [[maybe_unused]], intptr_t argn); +static const char* s_plugin_helper_GetConfigString2(plugin_id plid [[maybe_unused]], intptr_t index); + +static plugin_funcs s_pluginfuncs = { s_plugin_helper_WriteQMMLog, s_plugin_helper_VarArgs, s_plugin_helper_IsQVM, @@ -78,20 +78,20 @@ static pluginfuncs_t s_pluginfuncs = { }; // struct to store all the globals available to plugins -plugin_globals_t g_plugin_globals = { +plugin_globals g_plugin_globals = { 0, // final_return 0, // orig_return QMM_UNUSED, // high_result 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 pluginvars_t s_pluginvars = { +static plugin_vars s_pluginvars = { 0, // vmbase, set in plugin_load &g_plugin_globals.final_return, &g_plugin_globals.orig_return, @@ -99,7 +99,7 @@ static pluginvars_t s_pluginvars = { }; -const char* plugin_result_to_str(pluginres_t res) { +const char* plugin_result_to_str(plugin_res res) { switch (res) { GEN_CASE(QMM_UNUSED); GEN_CASE(QMM_ERROR); @@ -113,10 +113,10 @@ const char* plugin_result_to_str(pluginres_t 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_t& p, std::string file) { +int plugin_load(plugin& p, std::string file) { int ret = 0; - // if this plugin_t somehow already has a dll pointer, wipe it first + // if this plugin somehow already has a dll pointer, wipe it first if (p.dll) plugin_unload(p); @@ -135,7 +135,7 @@ int plugin_load(plugin_t& p, std::string file) { } // if this DLL is the same as another loaded plugin, cancel - for (plugin_t& t : g_plugins) { + for (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 @@ -229,21 +229,21 @@ int plugin_load(plugin_t& p, std::string file) { } -void plugin_unload(plugin_t& p) { +void plugin_unload(plugin& p) { if (p.dll) { if (p.QMM_Detach) p.QMM_Detach(); dlclose(p.dll); } - p = plugin_t(); + p = plugin(); } -static void s_plugin_helper_WriteQMMLog(plid_t plid, const char* text, int severity) { +static void s_plugin_helper_WriteQMMLog(plugin_id plid, const char* text, int severity) { if (severity < QMM_LOG_TRACE || severity > QMM_LOG_FATAL) severity = QMM_LOG_INFO; - plugininfo_t* plinfo = (plugininfo_t*)plid; + plugin_info* plinfo = (plugin_info*)plid; const char* logtag = plinfo->logtag; if (!logtag || !*logtag) logtag = plinfo->name; @@ -251,7 +251,7 @@ static void s_plugin_helper_WriteQMMLog(plid_t plid, const char* text, int sever } -static char* s_plugin_helper_VarArgs(plid_t plid [[maybe_unused]], const char* format, ...) { +static char* s_plugin_helper_VarArgs(plugin_id plid [[maybe_unused]], const char* format, ...) { va_list argptr; static char str[NUM_PLUGIN_STR_BUFFERS][1024]; static int index = 0; @@ -266,52 +266,52 @@ static char* s_plugin_helper_VarArgs(plid_t plid [[maybe_unused]], const char* f char* ret = str[index]; #ifdef _DEBUG - // LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnVarArgs(\"{}\", \"{}\") = \"{}\"\n", ((plugininfo_t*)plid)->name, format, ret); + // LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnVarArgs(\"{}\", \"{}\") = \"{}\"\n", ((plugin_info*)plid)->name, format, ret); #endif return ret; } -static int s_plugin_helper_IsQVM(plid_t plid [[maybe_unused]]) { +static int s_plugin_helper_IsQVM(plugin_id plid [[maybe_unused]]) { int ret = g_mod.vmbase != 0; #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnIsQVM(\"{}\") = {}\n", ((plugininfo_t*)plid)->name, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnIsQVM(\"{}\") = {}\n", ((plugin_info*)plid)->name, ret); #endif return ret; } -static const char* s_plugin_helper_EngMsgName(plid_t plid [[maybe_unused]], intptr_t msg) { +static const char* s_plugin_helper_EngMsgName(plugin_id plid [[maybe_unused]], intptr_t msg) { const char* ret = g_gameinfo.game->eng_msg_names(msg); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnEngMsgName(\"{}\", {}) = \"{}\"\n", ((plugininfo_t*)plid)->name, msg, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnEngMsgName(\"{}\", {}) = \"{}\"\n", ((plugin_info*)plid)->name, msg, ret); #endif return ret; } -static const char* s_plugin_helper_ModMsgName(plid_t plid [[maybe_unused]], intptr_t msg) { +static const char* s_plugin_helper_ModMsgName(plugin_id plid [[maybe_unused]], intptr_t msg) { const char* ret = g_gameinfo.game->mod_msg_names(msg); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnModMsgName(\"{}\", {}) = \"{}\"\n", ((plugininfo_t*)plid)->name, msg, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnModMsgName(\"{}\", {}) = \"{}\"\n", ((plugin_info*)plid)->name, msg, ret); #endif return ret; } -static intptr_t s_plugin_helper_GetIntCvar(plid_t plid [[maybe_unused]], const char* cvar) { +static intptr_t s_plugin_helper_GetIntCvar(plugin_id plid [[maybe_unused]], const char* cvar) { intptr_t ret = 0; if (cvar && *cvar) ret = ENG_SYSCALL(QMM_ENG_MSG[QMM_G_CVAR_VARIABLE_INTEGER_VALUE], cvar); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnGetIntCvar(\"{}\", \"{}\") = \"{}\"\n", ((plugininfo_t*)plid)->name, cvar, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnGetIntCvar(\"{}\", \"{}\") = \"{}\"\n", ((plugin_info*)plid)->name, cvar, ret); #endif return ret; @@ -319,7 +319,7 @@ static intptr_t s_plugin_helper_GetIntCvar(plid_t plid [[maybe_unused]], const c constexpr int MAX_CVAR_LEN = 1024; // most common cvar buffer size in SDK when calling G_CVAR_VARIABLE_STRING_BUFFER -static const char* s_plugin_helper_GetStrCvar(plid_t plid [[maybe_unused]], const char* cvar) { +static const char* s_plugin_helper_GetStrCvar(plugin_id plid [[maybe_unused]], const char* cvar) { static char str[NUM_PLUGIN_STR_BUFFERS][MAX_CVAR_LEN]; static int index = 0; @@ -333,37 +333,37 @@ static const char* s_plugin_helper_GetStrCvar(plid_t plid [[maybe_unused]], cons } #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnGetStrCvar(\"{}\", \"{}\") = \"{}\"\n", ((plugininfo_t*)plid)->name, cvar, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnGetStrCvar(\"{}\", \"{}\") = \"{}\"\n", ((plugin_info*)plid)->name, cvar, ret); #endif return ret; } -static const char* s_plugin_helper_GetGameEngine(plid_t plid [[maybe_unused]]) { +static const char* s_plugin_helper_GetGameEngine(plugin_id plid [[maybe_unused]]) { const char* ret = g_gameinfo.game->gamename_short; #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnGetGameEngine(\"{}\") = \"{}\"\n", ((plugininfo_t*)plid)->name, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnGetGameEngine(\"{}\") = \"{}\"\n", ((plugin_info*)plid)->name, ret); #endif return ret; } -static void s_plugin_helper_Argv(plid_t plid [[maybe_unused]], intptr_t argn, char* buf, intptr_t buflen) { +static void s_plugin_helper_Argv(plugin_id plid [[maybe_unused]], intptr_t argn, char* buf, intptr_t buflen) { if (buf && buflen) qmm_argv(argn, buf, buflen); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnArgv(\"{}\", {}) = \"{}\"\n", ((plugininfo_t*)plid)->name, argn, buf); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnArgv(\"{}\", {}) = \"{}\"\n", ((plugin_info*)plid)->name, argn, buf); #endif } // same as the SDK's Info_ValueForKey function -static const char* s_plugin_helper_InfoValueForKey(plid_t plid [[maybe_unused]], const char* userinfo, const char* key) { +static const char* s_plugin_helper_InfoValueForKey(plugin_id plid [[maybe_unused]], const char* userinfo, const char* key) { static std::string value[NUM_PLUGIN_STR_BUFFERS]; static int index = 0; @@ -394,14 +394,14 @@ static const char* s_plugin_helper_InfoValueForKey(plid_t plid [[maybe_unused]], } #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnInfoValueForKey(\"{}\", \"{}\", \"{}\") = \"{}\"\n", ((plugininfo_t*)plid)->name, userinfo, key, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnInfoValueForKey(\"{}\", \"{}\", \"{}\") = \"{}\"\n", ((plugin_info*)plid)->name, userinfo, key, ret); #endif return ret; } -static nlohmann::json s_plugin_cfg_get_node(plid_t plid [[maybe_unused]], std::string key) { +static nlohmann::json s_plugin_cfg_get_node(plugin_id plid [[maybe_unused]], std::string key) { if (key[0] == '/') key = key.substr(1); @@ -418,7 +418,7 @@ static nlohmann::json s_plugin_cfg_get_node(plid_t plid [[maybe_unused]], std::s return node; } -static const char* s_plugin_helper_ConfigGetStr(plid_t plid [[maybe_unused]], const char* key) { +static const char* s_plugin_helper_ConfigGetStr(plugin_id plid [[maybe_unused]], const char* key) { static std::string value[NUM_PLUGIN_STR_BUFFERS]; static int index = 0; @@ -428,28 +428,28 @@ static const char* s_plugin_helper_ConfigGetStr(plid_t plid [[maybe_unused]], co index = (index + 1) & NUM_PLUGIN_STR_BUFFER_MASK; value[index] = cfg_get_string(node, path_basename(key)); const char* ret = value[index].c_str(); - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnConfigGetStr(\"{}\", \"{}\") = \"{}\"\n", ((plugininfo_t*)plid)->name, key, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnConfigGetStr(\"{}\", \"{}\") = \"{}\"\n", ((plugin_info*)plid)->name, key, ret); return ret; } -static int s_plugin_helper_ConfigGetInt(plid_t plid [[maybe_unused]], const char* key) { +static int s_plugin_helper_ConfigGetInt(plugin_id plid [[maybe_unused]], const char* key) { nlohmann::json node = s_plugin_cfg_get_node(plid, key); int ret = cfg_get_int(node, path_basename(key)); - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnConfigGetInt(\"{}\", \"{}\") = {}\n", ((plugininfo_t*)plid)->name, key, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnConfigGetInt(\"{}\", \"{}\") = {}\n", ((plugin_info*)plid)->name, key, ret); return ret; } -static int s_plugin_helper_ConfigGetBool(plid_t plid [[maybe_unused]], const char* key) { +static int s_plugin_helper_ConfigGetBool(plugin_id plid [[maybe_unused]], const char* key) { nlohmann::json node = s_plugin_cfg_get_node(plid, key); int ret = (int)cfg_get_bool(node, path_basename(key)); - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnConfigGetBool(\"{}\", \"{}\") = {}\n", ((plugininfo_t*)plid)->name, key, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnConfigGetBool(\"{}\", \"{}\") = {}\n", ((plugin_info*)plid)->name, key, ret); return ret; } -static const char** s_plugin_helper_ConfigGetArrayStr(plid_t plid [[maybe_unused]], const char* key) { +static const char** s_plugin_helper_ConfigGetArrayStr(plugin_id plid [[maybe_unused]], const char* key) { static std::vector value[NUM_PLUGIN_STR_BUFFERS]; // plugin API needs to be C-compatible, so this vector stores the .c_str() of each string in the value vector static std::vector valuep[NUM_PLUGIN_STR_BUFFERS]; @@ -466,12 +466,12 @@ static const char** s_plugin_helper_ConfigGetArrayStr(plid_t plid [[maybe_unused valuep[index].push_back(s.c_str()); } valuep[index].push_back(nullptr); // null-terminate the array - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin ConfigGetArrayStr(\"{}\", \"{}\") = [{} items]\n", ((plugininfo_t*)plid)->name, key, value[index].size()); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin ConfigGetArrayStr(\"{}\", \"{}\") = [{} items]\n", ((plugin_info*)plid)->name, key, value[index].size()); return valuep[index].data(); } -static int* s_plugin_helper_ConfigGetArrayInt(plid_t plid [[maybe_unused]], const char* key) { +static int* s_plugin_helper_ConfigGetArrayInt(plugin_id plid [[maybe_unused]], const char* key) { static std::vector value[NUM_PLUGIN_STR_BUFFERS]; static int index = 0; @@ -482,13 +482,13 @@ static int* s_plugin_helper_ConfigGetArrayInt(plid_t plid [[maybe_unused]], cons value[index] = cfg_get_array_int(node, path_basename(key)); // insert length of the array as the first element value[index].insert(value[index].begin(), (int)value[index].size()); - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin ConfigGetArrayInt(\"{}\", \"{}\") = [{} items]\n", ((plugininfo_t*)plid)->name, key, value[index].size() - 1); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin ConfigGetArrayInt(\"{}\", \"{}\") = [{} items]\n", ((plugin_info*)plid)->name, key, value[index].size() - 1); return value[index].data(); } // get a configstring with G_GET_CONFIGSTRING, based on game engine type -static void s_plugin_helper_GetConfigString(plid_t plid [[maybe_unused]], intptr_t index, char* buf, intptr_t buflen) { +static void s_plugin_helper_GetConfigString(plugin_id plid [[maybe_unused]], intptr_t index, char* buf, intptr_t buflen) { // 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 @@ -501,19 +501,19 @@ static void s_plugin_helper_GetConfigString(plid_t plid [[maybe_unused]], intptr } #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnGetConfigString(\"{}\", {}) = \"{}\"\n", ((plugininfo_t*)plid)->name, index, buf); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnGetConfigString(\"{}\", {}) = \"{}\"\n", ((plugin_info*)plid)->name, index, buf); #endif } // broadcast a message to plugins' QMM_PluginMessage() functions -static int s_plugin_helper_PluginBroadcast(plid_t plid, const char* message, void* buf, intptr_t buflen) { +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_t& p : g_plugins) { + for (plugin& p : g_plugins) { // skip the calling plugin - if (p.plugininfo == (plugininfo_t*)plid) + if (p.plugininfo == (plugin_info*)plid) continue; // skip if the plugin doesn't have the function if (!p.QMM_PluginMessage) @@ -523,7 +523,7 @@ static int s_plugin_helper_PluginBroadcast(plid_t plid, const char* message, voi } #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnPluginBroadcast(\"{}\", \"{}\", {}, {}) = {} plugins called\n", ((plugininfo_t*)plid)->name, message, buf, buflen, total); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnPluginBroadcast(\"{}\", \"{}\", {}, {}) = {} plugins called\n", ((plugin_info*)plid)->name, message, buf, buflen, total); #endif return total; @@ -531,21 +531,21 @@ static int s_plugin_helper_PluginBroadcast(plid_t plid, const char* message, voi // send a message to a specific plugin's QMM_PluginMessage() functions -static int s_plugin_helper_PluginSend(plid_t plid, plid_t to_plid, const char* message, void* buf, intptr_t buflen) { +static int s_plugin_helper_PluginSend(plugin_id plid, plugin_id to_plid, const char* message, void* buf, intptr_t buflen) { // don't let a plugin call itself if (plid == to_plid) return 0; - for (plugin_t& p : g_plugins) { + for (plugin& p : g_plugins) { // if this is the destination plugin - if (p.plugininfo == (plugininfo_t*)to_plid) { + if (p.plugininfo == (plugin_info*)to_plid) { // if the plugin doesn't have the message function if (!p.QMM_PluginMessage) return 0; p.QMM_PluginMessage(plid, message, buf, buflen, 0); // 0 = is_broadcast #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnPluginSend(\"{}\", \"{}\", \"{}\", {}, {}) called\n", ((plugininfo_t*)plid)->name, ((plugininfo_t*)to_plid)->name, message, buf, buflen); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnPluginSend(\"{}\", \"{}\", \"{}\", {}, {}) called\n", ((plugin_info*)plid)->name, ((plugininfo_t*)to_plid)->name, message, buf, buflen); #endif return 1; @@ -556,13 +556,13 @@ static int s_plugin_helper_PluginSend(plid_t plid, plid_t to_plid, const char* m // register a new QVM function ID to the calling plugin (0 if unsuccessful) -static int s_plugin_helper_QVMRegisterFunc(plid_t plid) { +static int s_plugin_helper_QVMRegisterFunc(plugin_id plid) { int ret = 0; - // find the plugin_t for this plugin - for (plugin_t& p : g_plugins) { + // find the calling plugin + for (plugin& p : g_plugins) { // found it - if (p.plugininfo == (plugininfo_t*)plid) { + if (p.plugininfo == (plugin_info*)plid) { // make sure the plugin actually has a QVM handler func if (!p.QMM_QVMHandler) break; @@ -578,25 +578,25 @@ static int s_plugin_helper_QVMRegisterFunc(plid_t plid) { } } - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnRegisterQVMFunc(\"{}\") = {}\n", ((plugininfo_t*)plid)->name, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnRegisterQVMFunc(\"{}\") = {}\n", ((plugin_info*)plid)->name, ret); return ret; } // exec a given QVM function function ID -static int s_plugin_helper_QVMExecFunc(plid_t plid [[maybe_unused]], int instruction, int argc, int* argv) { - int ret = qvm_exec_ex(&g_mod.qvm, (size_t)instruction, argc, argv); +static int s_plugin_helper_QVMExecFunc(plugin_id plid [[maybe_unused]], int instruction, int argc, int* argv) { + int ret = qvm_exec_ex(&g_mod.vm, (size_t)instruction, argc, argv); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnQVMExecFunc(\"{}\", {}, {}) = {}\n", ((plugininfo_t*)plid)->name, instruction, argc, ret); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnQVMExecFunc(\"{}\", {}, {}) = {}\n", ((plugin_info*)plid)->name, instruction, argc, ret); #endif return ret; } -static const char* s_plugin_helper_Argv2(plid_t plid [[maybe_unused]], intptr_t argn) { +static const char* s_plugin_helper_Argv2(plugin_id plid [[maybe_unused]], intptr_t argn) { static char str[NUM_PLUGIN_STR_BUFFERS][1024]; static int index = 0; @@ -606,14 +606,14 @@ static const char* s_plugin_helper_Argv2(plid_t plid [[maybe_unused]], intptr_t qmm_argv(argn, str[index], sizeof(str[index])); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnArgv2(\"{}\", {}) = \"{}\"\n", ((plugininfo_t*)plid)->name, argn, str[index]); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnArgv2(\"{}\", {}) = \"{}\"\n", ((plugin_info*)plid)->name, argn, str[index]); #endif return str[index]; } -static const char* s_plugin_helper_GetConfigString2(plid_t plid [[maybe_unused]], intptr_t configindex) { +static const char* s_plugin_helper_GetConfigString2(plugin_id plid [[maybe_unused]], intptr_t configindex) { static char str[NUM_PLUGIN_STR_BUFFERS][1024]; static int index = 0; @@ -630,7 +630,7 @@ static const char* s_plugin_helper_GetConfigString2(plid_t plid [[maybe_unused]] strncpyz(str[index], (const char*)ret, sizeof(str[index])); #ifdef _DEBUG - LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnGetConfigString2(\"{}\", {}) = \"{}\"\n", ((plugininfo_t*)plid)->name, configindex, str[index]); + LOG(QMM_LOG_DEBUG, "QMM") << fmt::format("Plugin pfnGetConfigString2(\"{}\", {}) = \"{}\"\n", ((plugin_info*)plid)->name, configindex, str[index]); #endif return str[index]; diff --git a/src/qvm.c b/src/qvm.c index 4afa2e7..dc0b923 100644 --- a/src/qvm.c +++ b/src/qvm.c @@ -25,25 +25,25 @@ enum { QMM_LOG_TRACE, QMM_LOG_DEBUG, QMM_LOG_INFO, QMM_LOG_NOTICE, QMM_LOG_WARNI #endif -int qvm_load(qvm_t* qvm, const uint8_t* filemem, size_t filesize, qvmsyscall_t qvmsyscall, int verify_data, qvm_alloc_t* allocator) { - if (!qvm || qvm->memory || !filemem || !filesize || !qvmsyscall) +int qvm_load(qvm* vm, const uint8_t* filemem, size_t filesize, qvm_syscall qvmsyscall, int verify_data, qvm_alloc* allocator) { + if (!vm || vm->memory || !filemem || !filesize || !qvmsyscall) return 0; - if (filesize < sizeof(qvmheader_t)) { + if (filesize < sizeof(qvm_header)) { log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_load(): Invalid QVM file: too small for header\n"); goto fail; } - qvm->filesize = filesize; - qvm->qvmsyscall = qvmsyscall; - qvm->verify_data = verify_data; + vm->filesize = filesize; + vm->syscall = qvmsyscall; + vm->verify_data = verify_data; // if null, use default allocator (uses malloc/free) - qvm->allocator = allocator ? allocator : &qvm_allocator_default; + vm->allocator = allocator ? allocator : &qvm_allocator_default; - qvmheader_t header; + qvm_header header; // grab a copy of the header - memcpy(&header, filemem, sizeof(qvmheader_t)); + memcpy(&header, filemem, sizeof(qvm_header)); // check header fields for oddities if (header.magic != QVM_MAGIC) { @@ -73,10 +73,10 @@ int qvm_load(qvm_t* qvm, const uint8_t* filemem, size_t filesize, qvmsyscall_t q } // store numops in qvm object - qvm->instructioncount = header.instructioncount; + vm->instructioncount = header.instructioncount; // each opcode is 8 bytes long, calculate total size of instructions - size_t codeseglen = header.instructioncount * sizeof(qvmop_t); + size_t codeseglen = header.instructioncount * sizeof(qvm_op); if (!codeseglen) { log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_load(): Invalid QVM file: code segment length is 0\n"); goto fail; @@ -86,7 +86,7 @@ int qvm_load(qvm_t* qvm, const uint8_t* filemem, size_t filesize, qvmsyscall_t q // out with byte 0 (QVM_OP_UNDEF) which will immediately fail if the instruction pointer ends up // in that space QVM_NEXT_POW_2(codeseglen); - qvm->codeseglen = codeseglen; + vm->codeseglen = codeseglen; // data segment is all the data segment lengths combined (plus optional extra stack space) size_t dataseglen = header.datalen + header.litlen + header.bsslen + QVM_EXTRA_PROGRAMSTACK_SIZE; @@ -98,32 +98,32 @@ int qvm_load(qvm_t* qvm, const uint8_t* filemem, size_t filesize, qvmsyscall_t q size_t orig_dataseglen = dataseglen; // round data segment size up to next power of 2 for masking data accesses QVM_NEXT_POW_2(dataseglen); - qvm->dataseglen = dataseglen; + vm->dataseglen = dataseglen; // allow stack to use any extra space from rounding up - qvm->stacksize = QVM_PROGRAMSTACK_SIZE + (dataseglen - orig_dataseglen) + QVM_EXTRA_PROGRAMSTACK_SIZE; + vm->stacksize = QVM_PROGRAMSTACK_SIZE + (dataseglen - orig_dataseglen) + QVM_EXTRA_PROGRAMSTACK_SIZE; // allocate vm memory - qvm->memorysize = qvm->codeseglen + qvm->dataseglen; - qvm->memory = (uint8_t*)qvm->allocator->alloc(qvm->memorysize, qvm->allocator->ctx); - if (!qvm->memory) { - log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_load(): Memory allocation failed for size %zu\n", qvm->memorysize); + vm->memorysize = vm->codeseglen + vm->dataseglen; + vm->memory = (uint8_t*)vm->allocator->alloc(vm->memorysize, vm->allocator->ctx); + if (!vm->memory) { + log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_load(): Memory allocation failed for size %zu\n", vm->memorysize); goto fail; } // zero out memory - memset(qvm->memory, 0, qvm->memorysize); + memset(vm->memory, 0, vm->memorysize); // set segment pointers // | CODE | DATA | <- program stack starts here and grows down // program stack is for arguments and local variables - qvm->codesegment = (qvmop_t*)qvm->memory; - qvm->datasegment = qvm->memory + qvm->codeseglen; - qvm->stackptr = (int*)(qvm->datasegment + qvm->dataseglen); + vm->codesegment = (qvm_op*)vm->memory; + vm->datasegment = vm->memory + vm->codeseglen; + vm->stackptr = (int*)(vm->datasegment + vm->dataseglen); // set bounds of stack - qvm->stackhigh = qvm->stackptr; - qvm->stacklow = (int*)((uint8_t*)qvm->stackhigh - qvm->stacksize); + vm->stackhigh = vm->stackptr; + vm->stacklow = (int*)((uint8_t*)vm->stackhigh - vm->stacksize); // start loading instructions from the file's code offset into VM memory block const uint8_t* codeoffset = filemem + header.codeoffset; @@ -137,7 +137,7 @@ int qvm_load(qvm_t* qvm, const uint8_t* filemem, size_t filesize, qvmsyscall_t q } // get the opcode - qvmopcode_t opcode = (qvmopcode_t)*codeoffset; + qvm_opcode opcode = (qvm_opcode)*codeoffset; // make sure opcode is valid if (opcode < 0 || opcode >= QVM_OP_NUM_OPS) { @@ -146,7 +146,7 @@ int qvm_load(qvm_t* qvm, const uint8_t* filemem, size_t filesize, qvmsyscall_t q } // write opcode (to qvmop_t) - qvm->codesegment[i].op = opcode; + vm->codesegment[i].op = opcode; // move to next byte codeoffset++; @@ -179,7 +179,7 @@ int qvm_load(qvm_t* qvm, const uint8_t* filemem, size_t filesize, qvmsyscall_t q log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_load(): Invalid QVM file: can't read instruction %ud, reached end of file\n", i); goto fail; } - qvm->codesegment[i].param = *(int*)codeoffset; + vm->codesegment[i].param = *(int*)codeoffset; codeoffset += 4; break; @@ -190,79 +190,89 @@ int qvm_load(qvm_t* qvm, const uint8_t* filemem, size_t filesize, qvmsyscall_t q log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_load(): Invalid QVM file: can't read instruction %ud, reached end of file\n", i); goto fail; } - qvm->codesegment[i].param = (int)*codeoffset; + vm->codesegment[i].param = (int)*codeoffset; codeoffset++; break; default: // remaining instructions have no param - qvm->codesegment[i].param = 0; + vm->codesegment[i].param = 0; break; } } // copy data segment (including literals) to VM - memcpy(qvm->datasegment, filemem + header.dataoffset, header.datalen + header.litlen); + memcpy(vm->datasegment, filemem + header.dataoffset, header.datalen + header.litlen); // a winner is us return 1; fail: // :( - qvm_unload(qvm); + qvm_unload(vm); return 0; } -static qvm_t qvm_empty; -void qvm_unload(qvm_t* qvm) { - if (!qvm) +static qvm qvm_empty; +void qvm_unload(qvm* vm) { + if (!vm) return; - if (qvm->memory) - qvm->allocator->free(qvm->memory, qvm->memorysize, qvm->allocator->ctx); - *qvm = qvm_empty; + if (vm->memory) + vm->allocator->free(vm->memory, vm->memorysize, vm->allocator->ctx); + *vm = qvm_empty; } -int qvm_exec(qvm_t* qvm, int argc, int* argv) { - return qvm_exec_ex(qvm, 0, argc, argv); +int qvm_exec(qvm* vm, int argc, int* argv) { + return qvm_exec_ex(vm, 0, argc, argv); } -int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { - if (!qvm || !qvm->memory) { +int qvm_exec_ex(qvm* vm, size_t instruction, int argc, int* argv) { + if (!vm || !vm->memory) { log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_exec(%zu): Initialization error: given qvm is not loaded.\n", instruction); return 0; } // make sure instruction is in range - if (instruction >= qvm->instructioncount) { - log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_exec(%zu): Initialization error: given instruction id %zu is out of range [0, %zu).\n", instruction, instruction, qvm->instructioncount); + if (instruction >= vm->instructioncount) { + log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_exec(%zu): Initialization error: given instruction id %zu is out of range [0, %zu).\n", instruction, instruction, vm->instructioncount); return 0; } // start instruction pointer at given instruction - qvmop_t* opptr = qvm->codesegment + instruction; + qvm_op* opptr = vm->codesegment + instruction; // make sure instruction points to a QVM_OP_ENTER if (opptr->op != QVM_OP_ENTER) { const char* opname = "unknown"; if (opptr->op >= 0 && opptr->op < QVM_OP_NUM_OPS) - opname = opcodename[opptr->op]; + opname = qvm_opcodename[opptr->op]; log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_exec(%zu): Initialization error: instruction at %zu is %s (%d), expected QVM_OP_ENTER (3).\n", instruction, instruction, opname, opptr->op); return 0; } + // local copy of code segment pointer + qvm_op* codesegment = vm->codesegment; + // set up bitmasks for safety // code mask (masking qvmop_t indexes) - size_t codemask = (qvm->codeseglen / sizeof(qvmop_t)) - 1; + size_t codemask = (vm->codeseglen / sizeof(qvm_op)) - 1; + + // local copy of data segment pointer + uint8_t* datasegment = vm->datasegment; + // data mask - disable if verify_data is off by using a mask with all bits 1 - size_t datamask = qvm->verify_data ? qvm->dataseglen - 1 : (size_t)-1; + size_t datamask = vm->verify_data ? vm->dataseglen - 1 : (size_t)-1; // local "register" copy of stack pointer. this is purely for locality/speed. // it gets synced to qvm object before syscalls and restored after syscalls. // it also gets synced back to qvm object after execution completes - int* programstack = qvm->stackptr; + int* programstack = vm->stackptr; + // local copies + int* stacklow = vm->stacklow; + int* stackhigh = vm->stackhigh; // size of new stack frame, need to store RII, framesize, and vmMain args if (!argv) @@ -312,7 +322,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { int* opstackhigh = opstack; // current op - qvmopcode_t op; + qvm_opcode op; // hardcoded param for op int param; @@ -320,21 +330,21 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { do { // verify program stack pointer is in program stack // using > to allow starting at 1 past the end of block - if (programstack <= qvm->stacklow || programstack > qvm->stackhigh) { - ptrdiff_t stackusage = (uint8_t*)qvm->stackhigh - (uint8_t*)programstack; - log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: program stack overflow! Program stack size is currently %td, max is %zu.\n", instruction, opptr - qvm->codesegment, stackusage, qvm->stacksize); + if (programstack <= stacklow || programstack > stackhigh) { + ptrdiff_t stackusage = (uint8_t*)stackhigh - (uint8_t*)programstack; + log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: program stack overflow! Program stack size is currently %td, max is %zu.\n", instruction, opptr - codesegment, stackusage, vm->stacksize); goto fail; } // verify opstack pointer is in op stack // using > to allow starting at 1 past the end of block if (opstack <= opstacklow || opstack > opstackhigh) { ptrdiff_t stackusage = (uint8_t*)opstackhigh - (uint8_t*)opstack; - log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: opstack overflow! Opstack size is currently %td, max is %d.\n", instruction, opptr - qvm->codesegment, stackusage, QVM_OPSTACK_SIZE); + log_c(QMM_LOG_ERROR, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: opstack overflow! Opstack size is currently %td, max is %d.\n", instruction, opptr - codesegment, stackusage, QVM_OPSTACK_SIZE); goto fail; } // get the instruction's opcode and param - op = (qvmopcode_t)opptr->op; + op = (qvm_opcode)opptr->op; param = opptr->param; // throughout opcode handling, opptr points to the NEXT instruction to execute @@ -349,7 +359,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { default: // anything else // todo: dump stacks/memory? - log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: unhandled opcode %d\n", instruction, opptr - qvm->codesegment, op); + log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: unhandled opcode %d\n", instruction, opptr - codesegment, op); goto fail; case QVM_OP_NOP: @@ -376,7 +386,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { // verify the value saved in programstack[1] matches param, then remove stack frame (size=param). // then, grab RII from top of previous stack frame and then jump to it if (programstack[1] != param) { - log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: QVM_OP_LEAVE param (%d) does not match QVM_OP_ENTER param (%d)\n", instruction, opptr - qvm->codesegment, param, programstack[1]); + log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: QVM_OP_LEAVE param (%d) does not match QVM_OP_ENTER param (%d)\n", instruction, opptr - codesegment, param, programstack[1]); goto fail; } // clean up stack frame @@ -397,14 +407,14 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { // negative address means an engine trap if (jump_to < 0) { // store local program stack pointer in qvm object for re-entrancy - qvm->stackptr = programstack; + vm->stackptr = programstack; // pass call to game-specific syscall handler which will adjust pointer arguments // and then call the normal QMM syscall entry point so it can be routed to plugins - int ret = qvm->qvmsyscall(qvm->datasegment, -jump_to - 1, &programstack[2]); + int ret = vm->syscall(datasegment, -jump_to - 1, &programstack[2]); // program stack pointer in qvm object may have changed if re-entrant - programstack = qvm->stackptr; + programstack = vm->stackptr; // place return value on top of opstack like a VM function return value QVM_PUSH(ret); @@ -413,7 +423,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { // otherwise, normal VM function call // place RII in top slot of program stack - programstack[0] = (int)(opptr - qvm->codesegment); + programstack[0] = (int)(opptr - codesegment); // jump to VM function at address QVM_JUMP(jump_to); @@ -439,7 +449,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { case QVM_OP_LOCAL: // pushes a specified local variable address (relative to start of data segment) onto the opstack - QVM_PUSH( (int)((uint8_t*)programstack + param - qvm->datasegment) ); + QVM_PUSH( (int)((uint8_t*)programstack + param - datasegment) ); break; // branching @@ -534,28 +544,28 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { case QVM_OP_LOAD1: { // get 1-byte value at address stored in opstack[0] and store back in opstack[0] - uint8_t* src = qvm->datasegment + (opstack[0] & datamask); + uint8_t* src = datasegment + (opstack[0] & datamask); opstack[0] = (int)*src; break; } case QVM_OP_LOAD2: { // get 2-byte value at address stored in opstack[0] and store back in opstack[0] - uint16_t* src = (uint16_t*)(qvm->datasegment + (opstack[0] & datamask)); + uint16_t* src = (uint16_t*)(datasegment + (opstack[0] & datamask)); opstack[0] = (int)*src; break; } case QVM_OP_LOAD4: { // get 4-byte value at address stored in opstack[0] and store back in opstack[0] - int* src = (int*)(qvm->datasegment + (opstack[0] & datamask)); + int* src = (int*)(datasegment + (opstack[0] & datamask)); opstack[0] = *src; break; } case QVM_OP_STORE1: { // store 1-byte value from opstack[0] into address stored in opstack[1] - uint8_t* dst = qvm->datasegment + (opstack[1] & datamask); + uint8_t* dst = datasegment + (opstack[1] & datamask); *dst = (uint8_t)(opstack[0] & 0xFF); QVM_POPN(2); break; @@ -563,7 +573,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { case QVM_OP_STORE2: { // store 2-byte value from opstack[0] into address stored in opstack[1] - uint16_t* dst = (uint16_t*)(qvm->datasegment + (opstack[1] & datamask)); + uint16_t* dst = (uint16_t*)(datasegment + (opstack[1] & datamask)); *dst = (uint16_t)(opstack[0] & 0xFFFF); QVM_POPN(2); break; @@ -571,7 +581,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { case QVM_OP_STORE4: { // store 4-byte value from opstack[0] into address stored in opstack[1] - int* dst = (int*)(qvm->datasegment + (opstack[1] & datamask)); + int* dst = (int*)(datasegment + (opstack[1] & datamask)); *dst = opstack[0]; QVM_POPN(2); break; @@ -599,8 +609,8 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { count = ((srci + count) & datamask) - srci; count = ((dsti + count) & datamask) - dsti; - uint8_t* src = qvm->datasegment + srci; - uint8_t* dst = qvm->datasegment + dsti; + uint8_t* src = datasegment + srci; + uint8_t* dst = datasegment + dsti; memcpy(dst, src, count); @@ -641,7 +651,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { case QVM_OP_DIVI: // division if (opstack[0] == 0) { - log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: %s division by 0!\n", instruction, opptr - qvm->codesegment, opcodename[op]); + log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: %s division by 0!\n", instruction, opptr - codesegment, qvm_opcodename[op]); goto fail; } QVM_SOP( /= ); @@ -650,7 +660,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { case QVM_OP_DIVU: // unsigned division if (opstack[0] == 0) { - log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: %s division by 0!\n", instruction, opptr - qvm->codesegment, opcodename[op]); + log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: %s division by 0!\n", instruction, opptr - codesegment, qvm_opcodename[op]); goto fail; } QVM_UOP( /= ); @@ -659,7 +669,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { case QVM_OP_MODI: // modulus if (opstack[0] == 0) { - log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: %s division by 0!\n", instruction, opptr - qvm->codesegment, opcodename[op]); + log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: %s division by 0!\n", instruction, opptr - codesegment, qvm_opcodename[op]); goto fail; } QVM_SOP( %= ); @@ -668,7 +678,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { case QVM_OP_MODU: // unsigned modulus if (opstack[0] == 0) { - log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: %s division by 0!\n", instruction, opptr - qvm->codesegment, opcodename[op]); + log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: %s division by 0!\n", instruction, opptr - codesegment, qvm_opcodename[op]); goto fail; } QVM_UOP( %= ); @@ -738,7 +748,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { // float division // float 0s are all 0 bits but with either sign bit if (opstack[0] == 0 || opstack[0] == 0x80000000) { - log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: %s division by 0!\n", opptr - qvm->codesegment, opcodename[op]); + log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error at %td: %s division by 0!\n", opptr - codesegment, qvm_opcodename[op]); goto fail; } QVM_FOP( /= ); @@ -765,7 +775,7 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { // compare stored frame size like in QVM_OP_LEAVE if (programstack[1] != framesize) { - log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error after execution: stack frame size (%d) does not match entry stack frame size (%d)\n", opptr - qvm->codesegment, programstack[1], framesize); + log_c(QMM_LOG_FATAL, QMM_LOGGING_TAG, "qvm_exec(%zu): Runtime error after execution: stack frame size (%d) does not match entry stack frame size (%d)\n", opptr - codesegment, programstack[1], framesize); goto fail; } @@ -773,19 +783,19 @@ int qvm_exec_ex(qvm_t* qvm, size_t instruction, int argc, int* argv) { QVM_STACKFRAME(-framesize); // save our local program stack pointer back into the qvm object - qvm->stackptr = programstack; + vm->stackptr = programstack; // return value is stored on the top of the opstack (pushed just before QVM_OP_LEAVE) return opstack[0]; fail: - qvm_unload(qvm); + qvm_unload(vm); return 0; } // return a string name for the VM opcode -const char* opcodename[] = { +const char* qvm_opcodename[] = { "QVM_OP_UNDEF", "QVM_OP_NOP", "QVM_OP_BREAK", @@ -861,4 +871,4 @@ static void qvm_free_default(void* ptr, ptrdiff_t size, void* ctx) { } -qvm_alloc_t qvm_allocator_default = { qvm_alloc_default, qvm_free_default, NULL }; +qvm_alloc qvm_allocator_default = { qvm_alloc_default, qvm_free_default, NULL }; diff --git a/src/util.cpp b/src/util.cpp index 8ef7a9f..5ea538d 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -18,6 +18,7 @@ Created By: #include #include "util.h" + std::string path_normalize(std::string path) { // switch \ to / for (char& c : path) {