2
0
mirror of https://github.com/rehlds/metamod-r.git synced 2024-12-28 15:45:37 +03:00
metamod-r/metamod/src/metamod.h

386 lines
13 KiB
C
Raw Normal View History

2016-07-26 19:31:47 +03:00
#pragma once
2016-07-04 09:07:29 +03:00
#include "meta_api.h" // META_RES, etc
2016-07-26 19:31:47 +03:00
#include "mlist.h" // MPluginList, etc
#include "mreg.h" // MRegCmdList, etc
2016-07-04 09:07:29 +03:00
#include "conf_meta.h" // MConfig
2016-07-26 19:31:47 +03:00
#include "osdep.h" // NAME_MAX, etc
2016-07-04 09:07:29 +03:00
#include "types_meta.h" // mBOOL
2016-07-26 19:31:47 +03:00
#include "mplayer.h" // MPlayerList
#include "meta_eiface.h" // HL_enginefuncs_t, meta_enginefuncs_t
#include "engine_t.h" // engine_t, Engine
2016-07-04 09:07:29 +03:00
// file that lists plugins to load at startup
#define PLUGINS_INI "addons/metamod/plugins.ini"
2016-07-26 19:31:47 +03:00
#define OLD_PLUGINS_INI "metamod.ini"
2016-07-04 09:07:29 +03:00
// file that contains commands to metamod plugins at startup
#define EXEC_CFG "addons/metamod/exec.cfg"
2016-07-26 19:31:47 +03:00
#define OLD_EXEC_CFG "metaexec.cfg"
2016-07-04 09:07:29 +03:00
// previously, file that contained path for an override-gamedll
2016-07-26 19:31:47 +03:00
#define OLD_GAMEDLL_TXT "metagame.ini"
2016-07-04 09:07:29 +03:00
// generic config file
#define CONFIG_INI "addons/metamod/config.ini"
// cvar to contain version
2016-07-26 03:22:47 +03:00
extern cvar_t meta_version;
2016-07-04 09:07:29 +03:00
// Info about the game dll/mod.
2016-07-26 19:31:47 +03:00
struct gamedll_t
{
2016-07-04 09:07:29 +03:00
char name[NAME_MAX]; // ie "cstrike" (from gamedir)
2016-07-26 19:31:47 +03:00
const char *desc; // ie "Counter-Strike"
2016-07-04 09:07:29 +03:00
char gamedir[PATH_MAX]; // ie "/home/willday/half-life/cstrike"
char pathname[PATH_MAX]; // ie "/home/willday/half-life/cstrike/dlls/cs_i386.so"
2016-07-26 19:31:47 +03:00
char const *file; // ie "cs_i386.so"
2016-07-04 09:07:29 +03:00
char real_pathname[PATH_MAX]; // in case pathname overridden by bot, etc
DLHANDLE handle;
gamedll_funcs_t funcs; // dllapi_table, newapi_table
2016-07-26 19:31:47 +03:00
};
2016-07-26 03:22:47 +03:00
extern gamedll_t GameDLL;
2016-07-04 09:07:29 +03:00
// SDK variables for storing engine funcs and globals.
2016-07-26 03:22:47 +03:00
extern HL_enginefuncs_t g_engfuncs;
2016-07-26 19:31:47 +03:00
extern globalvars_t *gpGlobals;
2016-07-04 09:07:29 +03:00
// Our modified version of the engine funcs, to give to plugins.
2016-07-26 03:22:47 +03:00
extern meta_enginefuncs_t g_plugin_engfuncs;
2016-07-04 09:07:29 +03:00
// g_config structure.
extern MConfig *g_config;
2016-07-04 09:07:29 +03:00
// List of plugins loaded/opened/running.
extern MPluginList *g_plugins;
2016-07-04 09:07:29 +03:00
// List of command functions registered by plugins.
extern MRegCmdList *g_regCmds;
2016-07-04 09:07:29 +03:00
// List of cvar structures registered by plugins.
extern MRegCvarList *g_regCvars;
2016-07-04 09:07:29 +03:00
// List of user messages registered by gamedll.
extern MRegMsgList *g_regMsgs;
#ifdef UNFINISHED
// List of event/logline hooks requested by plugins.
extern MHookList *Hooks;
2016-07-26 19:31:47 +03:00
#endif
2016-07-04 09:07:29 +03:00
// Data provided to plugins.
// Separate copies to prevent plugins from modifying "readable" parts.
// See meta_api.h for meta_globals_t structure.
2016-07-26 03:22:47 +03:00
extern meta_globals_t PublicMetaGlobals;
extern meta_globals_t PrivateMetaGlobals;
2016-07-04 09:07:29 +03:00
// hook function tables
extern DLL_FUNCTIONS *pHookedDllFunctions;
extern NEW_DLL_FUNCTIONS *pHookedNewDllFunctions;
// (patch by hullu)
// Safety check for metamod-bot-plugin bugfix.
// engine_api->pfnRunPlayerMove calls dllapi-functions before it returns.
// This causes problems with bots running as metamod plugins, because
// metamod assumed that PublicMetaGlobals is free to be used.
2016-07-26 19:31:47 +03:00
// With call_count we can fix this by backuping up PublicMetaGlobals if
// it's already being used.
extern unsigned int CALL_API_count;
// stores previous requestid counter
extern int requestid_counter;
2016-07-04 09:07:29 +03:00
// (patch by BAILOPAN)
2016-07-04 09:07:29 +03:00
// Holds cached player info, right now only things for querying cvars
// Max players is always 32, small enough that we can use a static array
2016-07-26 03:22:47 +03:00
extern MPlayerList g_Players;
2016-07-04 09:07:29 +03:00
2016-07-26 19:31:47 +03:00
void metamod_startup();
2016-07-04 09:07:29 +03:00
2016-07-26 19:31:47 +03:00
mBOOL meta_init_gamedll();
mBOOL meta_load_gamedll();
2016-07-04 09:07:29 +03:00
2016-07-26 19:31:47 +03:00
// lotsa macros...
2016-07-04 09:07:29 +03:00
// These are the meat of the metamod processing, and are as ugly as (or
// uglier) than they look. This is done via macros, because of the varying
// parameter types (int, void, edict_t*, etc) as well as varying
// function-pointer types and different api tables (dllapi, newapi,
// engine), which just can't be passed to a function. And, since the
// operation is similar for each api call, I didn't want to keep
// duplicating code all over the place. Thus the ugly macros.
//
// The basic operation is, for each api call:
// - iterate through list of plugins
// - for each plugin, if it provides this api call, then call the
// function in the plugin
// - call the "real" function (in the game dll, or from the engine)
// - for each plugin, check for a "post" version of the function, and call
// if present
//
//
// Also, for any api call, each plugin has the opportunity to replace the
// real routine, in two ways:
// - prevent the real routine from being called ("supercede")
// - allow the real routine to be called, but change the value that's
// returned ("override")
//
// Thus after each plugin is called, its META_RETURN flag is checked, and
// action taken appropriately. Note that supercede/override only affects
// the _real_ routine; other plugins will still be called.
//
// In addition to the SUPERCEDE and OVERRIDE flags, there are two
// additional flags a plugin can return:
// - HANDLED ("I did something here")
// - IGNORED ("I didn't really do anything")
//
// These aren't used by metamod itself, but could be used by plugins to
// get an idea if a previous plugin did anything.
//
//
// The 5 basic macros are:
// SETUP
// CALL_PLUGIN
// CALL_GAME and CALL_ENGINE
// RETURN
//
// These 5 are actually used to build second level macros for each api type
// (dllapi, newapi, engine), with the CALL_PLUGIN macro being used twice
// (before and after). Altogether, they end up expanding to approx 150
// lines of code for _each_ api call. Ack, ugly indeed.
//
// However, due to some functions returning 'void', and others returning an
// actual value, I had to have separate macros for the two, since I
// couldn't seem to generalize the two into a form that the compiler would
// accept. Thus there are "_void" versions of the 5 macros; these are
// listed first.
2016-07-26 19:31:47 +03:00
// macros for void-returning functions
// declare/init some variables
#define SETUP_API_CALLS_void(FN_TYPE, pfnName, api_info_table) \
int i; \
2016-07-26 19:31:47 +03:00
META_RES mres = MRES_UNSET, status = MRES_UNSET, prev_mres = MRES_UNSET; \
MPlugin *iplug; \
2016-07-26 19:31:47 +03:00
FN_TYPE pfn_routine = NULL; \
int loglevel = api_info_table.pfnName.loglevel; \
const char *pfn_string = api_info_table.pfnName.name; \
meta_globals_t backup_meta_globals; \
/* fix bug with metamod-bot-plugins (hullu)*/ \
if (CALL_API_count++>0) \
/* backup publicmetaglobals */ \
backup_meta_globals = PublicMetaGlobals;
// call each plugin
#define CALL_PLUGIN_API_void(post, pfnName, pfn_args, api_table) \
2016-07-26 19:31:47 +03:00
prev_mres = MRES_UNSET; \
for (i = 0; i < g_plugins->endlist; i++) { \
iplug = &g_plugins->plist[i]; \
if (iplug->status != PL_RUNNING) \
continue; \
2016-07-26 19:31:47 +03:00
if (iplug->api_table && (pfn_routine = iplug->api_table->pfnName)); \
else \
/* plugin doesn't provide this function */ \
continue; \
/* initialize PublicMetaGlobals */ \
PublicMetaGlobals.mres = MRES_UNSET; \
PublicMetaGlobals.prev_mres = prev_mres; \
PublicMetaGlobals.status = status; \
/* call plugin */ \
META_DEBUG(loglevel, ("Calling %s:%s%s()", iplug->file, pfn_string, (post?"_Post":""))); \
pfn_routine pfn_args; \
/* plugin's result code */ \
2016-07-26 19:31:47 +03:00
mres = PublicMetaGlobals.mres; \
if (mres > status) \
status = mres; \
/* save this for successive plugins to see */ \
prev_mres = mres; \
2016-07-26 19:31:47 +03:00
if (mres == MRES_UNSET) \
META_ERROR("Plugin didn't set meta_result: %s:%s%s()", iplug->file, pfn_string, (post?"_Post":"")); \
2016-07-26 19:31:47 +03:00
if (post && mres == MRES_SUPERCEDE) \
META_ERROR("MRES_SUPERCEDE not valid in Post functions: %s:%s%s()", iplug->file, pfn_string, (post?"_Post":"")); \
}
2016-07-04 09:07:29 +03:00
// call "real" function, from gamedll
#define CALL_GAME_API_void(pfnName, pfn_args, api_table) \
CALL_API_count--; \
2016-07-26 19:31:47 +03:00
if (status == MRES_SUPERCEDE) { \
META_DEBUG(loglevel, ("Skipped (supercede) %s:%s()", GameDLL.file, pfn_string)); \
/* don't return here; superceded game routine, but still allow \
* _post routines to run. \
*/ \
} \
2016-07-26 19:31:47 +03:00
else if (GameDLL.funcs.api_table) { \
pfn_routine = GameDLL.funcs.api_table->pfnName; \
if (pfn_routine) { \
META_DEBUG(loglevel, ("Calling %s:%s()", GameDLL.file, pfn_string)); \
pfn_routine pfn_args; \
} \
/* don't complain for NULL routines in NEW_DLL_FUNCTIONS */ \
2016-07-26 19:31:47 +03:00
else if ((void *)GameDLL.funcs.api_table != (void *)GameDLL.funcs.newapi_table) { \
META_ERROR("Couldn't find api call: %s:%s", GameDLL.file, pfn_string); \
2016-07-26 19:31:47 +03:00
status = MRES_UNSET; \
} \
} \
else { \
META_DEBUG(loglevel, ("No api table defined for api call: %s:%s", GameDLL.file, pfn_string)); \
} \
CALL_API_count++;
// call "real" function, from engine
#define CALL_ENGINE_API_void(pfnName, pfn_args) \
CALL_API_count--; \
2016-07-26 19:31:47 +03:00
if (status == MRES_SUPERCEDE) { \
META_DEBUG(loglevel, ("Skipped (supercede) engine:%s()", pfn_string)); \
/* don't return here; superceded game routine, but still allow \
* _post routines to run. \
*/ \
} \
else { \
2016-07-26 19:31:47 +03:00
pfn_routine = g_engine.funcs->pfnName; \
if (pfn_routine) { \
META_DEBUG(loglevel, ("Calling engine:%s()", pfn_string)); \
pfn_routine pfn_args; \
} \
else { \
META_ERROR("Couldn't find api call: engine:%s", pfn_string); \
2016-07-26 19:31:47 +03:00
status = MRES_UNSET; \
} \
} \
CALL_API_count++;
// return (void)
2016-07-04 09:07:29 +03:00
#define RETURN_API_void() \
if (--CALL_API_count>0) \
/*restore backup*/ \
PublicMetaGlobals = backup_meta_globals; \
2016-07-04 09:07:29 +03:00
return;
2016-07-26 19:31:47 +03:00
// macros for type-returning functions
// declare/init some variables
2016-07-26 19:31:47 +03:00
#define SETUP_API_CALLS(ret_t, ret_init, FN_TYPE, pfnName, api_info_table) \
int i; \
2016-07-26 19:31:47 +03:00
ret_t dllret = ret_init; \
ret_t override_ret = ret_init; \
ret_t pub_override_ret = ret_init; \
ret_t orig_ret = ret_init; \
ret_t pub_orig_ret = ret_init; \
META_RES mres = MRES_UNSET, status = MRES_UNSET, prev_mres = MRES_UNSET; \
MPlugin *iplug; \
2016-07-26 19:31:47 +03:00
FN_TYPE pfn_routine = NULL; \
int loglevel = api_info_table.pfnName.loglevel; \
const char *pfn_string = api_info_table.pfnName.name; \
meta_globals_t backup_meta_globals; \
/*Fix bug with metamod-bot-plugins*/ \
if (CALL_API_count++>0) \
/*Backup PublicMetaGlobals*/ \
backup_meta_globals = PublicMetaGlobals;
// call each plugin
#define CALL_PLUGIN_API(post, ret_init, pfnName, pfn_args, MRES_TYPE, api_table) \
2016-07-26 19:31:47 +03:00
override_ret = ret_init; \
prev_mres = MRES_UNSET; \
for (i = 0; i < g_plugins->endlist; i++) { \
if (g_plugins->plist[i].status != PL_RUNNING) \
continue; \
2016-07-26 19:31:47 +03:00
iplug = &g_plugins->plist[i]; \
if (iplug->api_table && (pfn_routine = iplug->api_table->pfnName)); \
else \
/* plugin doesn't provide this function */ \
continue; \
/* initialize PublicMetaGlobals */ \
PublicMetaGlobals.mres = MRES_UNSET; \
PublicMetaGlobals.prev_mres = prev_mres; \
PublicMetaGlobals.status = status; \
pub_orig_ret = orig_ret; \
PublicMetaGlobals.orig_ret = &pub_orig_ret; \
2016-07-26 19:31:47 +03:00
if (status == MRES_TYPE) { \
pub_override_ret = override_ret; \
PublicMetaGlobals.override_ret = &pub_override_ret; \
} \
/* call plugin */ \
META_DEBUG(loglevel, ("Calling %s:%s%s()", iplug->file, pfn_string, (post?"_Post":""))); \
2016-07-26 19:31:47 +03:00
dllret = pfn_routine pfn_args; \
/* plugin's result code */ \
2016-07-26 19:31:47 +03:00
mres = PublicMetaGlobals.mres; \
if (mres > status) \
status = mres; \
/* save this for successive plugins to see */ \
prev_mres = mres; \
2016-07-26 19:31:47 +03:00
if (mres == MRES_TYPE) \
override_ret = pub_override_ret = dllret; \
2016-07-26 19:31:47 +03:00
else if (mres == MRES_UNSET) \
META_ERROR("Plugin didn't set meta_result: %s:%s%s()", iplug->file, pfn_string, (post?"_Post":"")); \
2016-07-26 19:31:47 +03:00
else if (post && mres == MRES_SUPERCEDE) \
META_ERROR("MRES_SUPERCEDE not valid in Post functions: %s:%s%s()", iplug->file, pfn_string, (post?"_Post":"")); \
2016-07-04 09:07:29 +03:00
}
// call "real" function, from gamedll
#define CALL_GAME_API(pfnName, pfn_args, api_table) \
CALL_API_count--; \
2016-07-26 19:31:47 +03:00
if (status == MRES_SUPERCEDE) { \
META_DEBUG(loglevel, ("Skipped (supercede) %s:%s()", GameDLL.file, pfn_string)); \
orig_ret = pub_orig_ret = override_ret; \
PublicMetaGlobals.orig_ret = &pub_orig_ret; \
/* don't return here; superceded game routine, but still allow \
* _post routines to run. \
*/ \
} \
2016-07-26 19:31:47 +03:00
else if (GameDLL.funcs.api_table) { \
pfn_routine = GameDLL.funcs.api_table->pfnName; \
if (pfn_routine) { \
META_DEBUG(loglevel, ("Calling %s:%s()", GameDLL.file, pfn_string)); \
2016-07-26 19:31:47 +03:00
dllret = pfn_routine pfn_args; \
orig_ret = dllret; \
} \
/* don't complain for NULL routines in NEW_DLL_FUNCTIONS */ \
2016-07-26 19:31:47 +03:00
else if ((void *)GameDLL.funcs.api_table != (void *)GameDLL.funcs.newapi_table) { \
META_ERROR("Couldn't find api call: %s:%s", GameDLL.file, pfn_string); \
2016-07-26 19:31:47 +03:00
status = MRES_UNSET; \
} \
} \
else { \
META_DEBUG(loglevel, ("No api table defined for api call: %s:%s", GameDLL.file, pfn_string)); \
} \
CALL_API_count++;
// call "real" function, from engine
#define CALL_ENGINE_API(pfnName, pfn_args) \
CALL_API_count--; \
2016-07-26 19:31:47 +03:00
if (status == MRES_SUPERCEDE) { \
META_DEBUG(loglevel, ("Skipped (supercede) engine:%s()", pfn_string)); \
orig_ret = pub_orig_ret = override_ret; \
PublicMetaGlobals.orig_ret = &pub_orig_ret; \
/* don't return here; superceded game routine, but still allow \
* _post routines to run. \
*/ \
} \
else { \
2016-07-26 19:31:47 +03:00
pfn_routine = g_engine.funcs->pfnName; \
if (pfn_routine) { \
META_DEBUG(loglevel, ("Calling engine:%s()", pfn_string)); \
2016-07-26 19:31:47 +03:00
dllret = pfn_routine pfn_args; \
orig_ret = dllret; \
} \
else { \
META_ERROR("Couldn't find api call: engine:%s", pfn_string); \
2016-07-26 19:31:47 +03:00
status = MRES_UNSET; \
} \
} \
CALL_API_count++;
2016-07-04 09:07:29 +03:00
// return a value
#define RETURN_API() \
if (--CALL_API_count>0) \
/*Restore backup*/ \
PublicMetaGlobals = backup_meta_globals; \
2016-07-26 19:31:47 +03:00
if (status == MRES_OVERRIDE) { \
META_DEBUG(loglevel, ("Returning (override) %s()", pfn_string)); \
2016-07-26 19:31:47 +03:00
return override_ret; \
} \
else \
2016-07-26 19:31:47 +03:00
return orig_ret;