Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 68 additions & 73 deletions include/game_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,109 +19,104 @@ Created By:
#include "qmmapi.h"
#include "qvm.h"

struct supportedgame;
struct supportedgame_funcs {
// this section is made by GEN_INFO(GAME)
// engine/mod API type
enum APIType {
QMM_API_ERROR,

QMM_API_QVM,

QMM_API_DLLENTRY,
QMM_API_GETGAMEAPI,
QMM_API_GETMODULEAPI,
};
const char* APIType_Name(APIType);
const char* APIType_Function(APIType);

struct api_supportedgame;
// this struct is defined by GEN_GAME_FUNCS_QVM(GAME) or GEN_GAME_FUNCS(GAME)
struct api_supportedgame_funcs {
int* qmm_eng_msgs; // array of engine messages used by QMM
int* qmm_mod_msgs; // array of mod messages used by QMM
const char* (*pfnEngMsgNames)(intptr_t); // pointer to a function that returns a string for a given engine message
const char* (*pfnEngMsgNames)(intptr_t); // pointer to a function that returns a string for a given api message
const char* (*pfnModMsgNames)(intptr_t); // pointer to a function that returns a string for a given mod message

// this section is made by GEN_DLLQVM(GAME), GEN_DLL(GAME), or GEN_GGA(GAME)
bool(*pfnAutoDetect)(bool, supportedgame*); // pointer to a function that handles auto-detection logic for a game (NULL = no auto-detection)
qvm_syscall pfnqvmsyscall; // pointer to a function that handles mod->engine calls from a QVM (NULL = not supported)
mod_dllEntry pfndllEntry; // pointer to a function that handles dllEntry entry for a game (NULL = not supported)
mod_GetGameAPI pfnGetGameAPI; // pointer to a function that handles GetGameAPI entry for a game (NULL = not supported)
bool(*pfnModLoad)(void*, bool); // pointer to a function that handles mod loading logic after a DLL is loaded
bool(*pfnAutoDetect)(api_supportedgame*, APIType); // pointer to a function that handles auto-detection logic for a game. return true to say "that's me!"
void*(*pfnEntry)(void*, void*, APIType); // pointer to a function that handles entry point logic for a game
bool(*pfnModLoad)(void*, APIType); // pointer to a function that handles mod loading logic after a DLL is loaded with LoadLibrary/dlopen
void(*pfnModUnload)(); // pointer to a function that handles mod unloading logic before a DLL is unloaded

qvm_syscall pfnQVMSyscall; // pointer to a function that handles mod->engine calls from a QVM (NULL = not supported)
};


// some information for each game engine supported by QMM
struct supportedgame {
struct api_supportedgame {
const char* dllname; // default dll mod filename
const char* qvmname; // default qvm mod filename (NULL = not supported)
const char* moddir; // default moddir name
const char* gamename_long; // long, descriptive, game name

// this section is made by GEN_FUNCS(GAME)
// this section is made by GEN_GAME_INFO(GAME)
const char* gamename_short; // short initials for game
supportedgame_funcs* funcs; // function pointers for this game
api_supportedgame_funcs* funcs; // function pointers for this game

int max_syscall_args; // max number of syscall args that this game needs (unused for now, but nice to have easily available)
int max_vmmain_args; // max number of vmmain args that this game needs (unused for now, but nice to have easily available)
};

extern std::vector<supportedgame> g_supportedgames;
extern std::vector<api_supportedgame> api_supportedgames;

// macros to make game support a bit easier to do

// used at the top of game_api.cpp and game_XYZ.cpp
// ======
// generate extern for each game's functions
#define GEN_EXTS(game) extern supportedgame_funcs game##_funcs;

// used in supportedgames entry in game_api.cpp
// ======
// generate extern for each game's shortcode and supportedgame_funcs struct (used in game_api.cpp)
#define GEN_INFO(game) #game , &game##_funcs

// used in game_XYZ.cpp
// ======
// generate struct info for the game-specific functions and arrays

// dllEntry/vmMain game with QVM support
#define GEN_DLLQVM(game) \
static const char* game##_eng_msg_names(intptr_t); \
static const char* game##_mod_msg_names(intptr_t); \
static bool game##_autodetect(bool, supportedgame*); \
static intptr_t game##_syscall(intptr_t cmd, ...); \
static intptr_t game##_vmMain(intptr_t cmd, ...); \
static int game##_qvmsyscall(uint8_t*, int, int*); \
static void game##_dllEntry(eng_syscall); \
static bool game##_mod_load(void*, bool); \
static void game##_mod_unload(); \
supportedgame_funcs game##_funcs = { \
game##_qmm_eng_msgs, game##_qmm_mod_msgs, game##_eng_msg_names, game##_mod_msg_names, \
game##_autodetect, game##_qvmsyscall, game##_dllEntry, nullptr, \
game##_mod_load, game##_mod_unload \
}
// generate extern for each game's functions (used at the top of game_api.cpp and game_XYZ.cpp)
#define GEN_GAME_EXTS(game) extern api_supportedgame_funcs game##_funcs;

// generate extern for each game's shortcode and funcs struct (used in supportedgames entry in game_api.cpp)
#define GEN_GAME_INFO(game) #game , &game##_funcs

// generate struct info for the game-specific functions and arrays (used in game_XYZ.cpp)

// dllEntry/vmMain game with no QVM support
#define GEN_DLL(game) \
static const char* game##_eng_msg_names(intptr_t); \
static const char* game##_mod_msg_names(intptr_t); \
static bool game##_autodetect(bool, supportedgame*); \
// game with QVM support
#define GEN_GAME_FUNCS_QVM(game) \
static const char* game##_EngMsgNames(intptr_t); \
static const char* game##_ModMsgNames(intptr_t); \
static bool game##_AutoDetect(api_supportedgame*, APIType); \
static void* game##_Entry(void*, void*, APIType); \
static bool game##_ModLoad(void*, APIType); \
static void game##_ModUnload(); \
static intptr_t game##_syscall(intptr_t cmd, ...); \
static intptr_t game##_vmMain(intptr_t cmd, ...); \
static void game##_dllEntry(eng_syscall); \
static bool game##_mod_load(void*, bool); \
static void game##_mod_unload(); \
supportedgame_funcs game##_funcs = { \
game##_qmm_eng_msgs, game##_qmm_mod_msgs, game##_eng_msg_names, game##_mod_msg_names, \
game##_autodetect, nullptr, game##_dllEntry, nullptr, \
game##_mod_load, game##_mod_unload \
static int game##_QVMSyscall(uint8_t*, int, int*); \
api_supportedgame_funcs game##_funcs = { \
game##_qmm_eng_msgs, game##_qmm_mod_msgs, \
game##_EngMsgNames, game##_ModMsgNames, \
game##_AutoDetect, game##_Entry, \
game##_ModLoad, game##_ModUnload, \
game##_QVMSyscall, \
}

// GetGameAPI game
#define GEN_GGA(game) \
static const char* game##_eng_msg_names(intptr_t); \
static const char* game##_mod_msg_names(intptr_t); \
static bool game##_autodetect(bool, supportedgame*); \
// game with no QVM support
#define GEN_GAME_FUNCS(game) \
static const char* game##_EngMsgNames(intptr_t); \
static const char* game##_ModMsgNames(intptr_t); \
static bool game##_AutoDetect(api_supportedgame*, APIType); \
static void* game##_Entry(void*, void*, APIType); \
static bool game##_ModLoad(void*, APIType); \
static void game##_ModUnload(); \
static intptr_t game##_syscall(intptr_t cmd, ...); \
static intptr_t game##_vmMain(intptr_t cmd, ...); \
static void* game##_GetGameAPI(void*, void*); \
static bool game##_mod_load(void*, bool); \
static void game##_mod_unload(); \
supportedgame_funcs game##_funcs = { \
game##_qmm_eng_msgs, game##_qmm_mod_msgs, game##_eng_msg_names, game##_mod_msg_names, \
game##_autodetect, nullptr, nullptr, game##_GetGameAPI, \
game##_mod_load, game##_mod_unload \
api_supportedgame_funcs game##_funcs = { \
game##_qmm_eng_msgs, game##_qmm_mod_msgs, \
game##_EngMsgNames, game##_ModMsgNames, \
game##_AutoDetect, game##_Entry, \
game##_ModLoad, game##_ModUnload, \
nullptr, \
}

// generate a case/string line for use in the _msg_names functions
// generate a case/string line for use in the *MsgNames functions
#define GEN_CASE(x) case x: return #x

// a list of all the engine messages/constants used by QMM. if you change this, update the GEN_QMM_MSGS macro
// a list of all the engine messages/constants used by QMM. if you change this, update the GEN_GAME_QMM_MSGS macro
enum {
// general purpose
QMM_G_PRINT, QMM_G_ERROR, QMM_G_ARGV, QMM_G_ARGC, QMM_G_SEND_CONSOLE_COMMAND, QMM_G_GET_CONFIGSTRING,
Expand All @@ -131,11 +126,11 @@ enum {
QMM_G_FS_FOPEN_FILE, QMM_G_FS_READ, QMM_G_FS_WRITE, QMM_G_FS_FCLOSE_FILE, QMM_EXEC_APPEND, QMM_FS_READ,
};

// a list of all the mod messages used by QMM. if you change this, update the GEN_QMM_MSGS macro
// a list of all the mod messages used by QMM. if you change this, update the GEN_GAME_QMM_MSGS macro
enum { QMM_GAME_INIT, QMM_GAME_SHUTDOWN, QMM_GAME_CONSOLE_COMMAND, };

// macro to easily output game-specific message values to match the enums above. this macro goes in game_*.cpp
#define GEN_QMM_MSGS(game) \
#define GEN_GAME_QMM_MSGS(game) \
static int game##_qmm_eng_msgs[] = { \
G_PRINT, G_ERROR, G_ARGV, G_ARGC, G_SEND_CONSOLE_COMMAND, G_GET_CONFIGSTRING, \
G_CVAR_REGISTER, G_CVAR_VARIABLE_STRING_BUFFER, G_CVAR_VARIABLE_INTEGER_VALUE, CVAR_SERVERINFO, CVAR_ROM, \
Expand Down Expand Up @@ -235,7 +230,7 @@ constexpr int QMM_MAX_SYSCALL_ARGS = 17;
// ----- QVM stuff -----
// ---------------------

// these macros handle qvm syscall arguments in GAME_qvmsyscall functions in game_*.cpp
// these macros handle qvm syscall arguments in GAME_QVMSyscall functions in game_*.cpp

// this gets an argument value (evaluate to an intptr_t)
#define VMARG(arg) (intptr_t)args[arg]
Expand Down
3 changes: 2 additions & 1 deletion include/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ struct gameinfo {
std::string cfg_path; // qmm config file path
eng_syscall pfnsyscall = nullptr; // game-specific wrapper for syscall. given to plugins and called by QMM
mod_vmMain pfnvmMain = nullptr; // game-specific wrapper for vmMain. given to plugins and called by QMM
supportedgame* game = nullptr; // loaded engine from supported games table from game_api.cpp
api_supportedgame* game = nullptr; // loaded engine from supported games table from game_api.cpp
void* qmm_module_ptr = nullptr; // qmm module pointer
bool is_auto_detected = false; // was this engine auto-detected?
bool is_shutdown = false; // is game shutting down due to G_ERROR? avoids calling G_ERROR again from GAME_SHUTDOWN
APIType api = QMM_API_ERROR; // engine api that QMM was loaded with
};
extern gameinfo g_gameinfo;

Expand Down
17 changes: 9 additions & 8 deletions include/mod.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ Created By:
#include "qmmapi.h"
#include "qvm.h"

struct mod {
void* dll = nullptr;
qvm vm = {};
intptr_t vmbase = 0;
std::string path;
struct qmm_mod {
std::string path; // mod file path
qvm vm = {}; // QVM object
void* dll = nullptr; // OS DLL handle
intptr_t vmbase = 0; // base data segment address for QVMs (0 if DLL mod)
APIType api = QMM_API_ERROR; // engine api the mod DLL was loaded with
};

extern mod g_mod;
extern qmm_mod g_mod;

bool mod_load(mod& mod, std::string file);
void mod_unload(mod& mod);
bool mod_load(qmm_mod& mod, std::string file);
void mod_unload(qmm_mod& mod);

#endif // QMM2_MOD_H

14 changes: 6 additions & 8 deletions include/osdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,13 @@ Created By:
#define EXT_DLL "dll"
#define EXT_QVM "qvm"

#define PATH_MAX 4096
#define strcasecmp _stricmp
#define PATH_MAX MAX_PATH
#define dlopen(file, x) ((void*)LoadLibrary(file))
#define dlsym(dll, func) ((void*)GetProcAddress((HMODULE)(dll), (func)))
#define dlclose(dll) FreeLibrary((HMODULE)(dll))
#define mkdir(path, x) _mkdir(path)
#define osdef_get_milliseconds GetTickCount64
const char* dlerror(); // this will return the last error from any win32 function, not just library functions
#define dlsym(dll, func) ((void*)GetProcAddress((HMODULE)(dll), (func)))
#define dlclose(dll) FreeLibrary((HMODULE)(dll))
#define mkdir(path, x) _mkdir(path)
#define osdef_get_milliseconds GetTickCount64
const char* dlerror(); // this will return the last error from any win32 function, not just library functions

#elif defined(QMM_OS_LINUX)

Expand All @@ -67,7 +66,6 @@ Created By:
#define EXT_DLL "so"
#define EXT_QVM "qvm"
uint64_t osdef_get_milliseconds();
void MessageBoxA(void* handle, const char* message, const char* title, int flags);

#else // !QMM_OS_WINDOWS && !QMM_OS_LINUX

Expand Down
10 changes: 5 additions & 5 deletions include/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ using plugin_pluginmessage = void (*)(plugin_id from_plid, const char* message,
// QMM_QVMHandler
using plugin_qvmhandler = int (*)(int cmd, int* args);

struct plugin {
struct qmm_plugin {
void* dll = nullptr;
std::string path;
plugin_query QMM_Query = nullptr;
Expand All @@ -54,18 +54,18 @@ struct plugin_globals {

extern plugin_globals g_plugin_globals;

extern std::vector<plugin> g_plugins;
extern std::vector<qmm_plugin> 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<int, plugin*> g_registered_qvm_funcs;
extern std::map<int, qmm_plugin*> g_registered_qvm_funcs;

const char* plugin_result_to_str(plugin_res res);

// returns: -1 if failed to load and don't continue, 0 if failed to load and continue, 1 if loaded
int plugin_load(plugin& p, std::string file);
int plugin_load(qmm_plugin& p, std::string file);

void plugin_unload(plugin& p);
void plugin_unload(qmm_plugin& p);

#endif // QMM2_PLUGIN_H
Loading