Compiling
You'll need the Half-Life SDK, of course. In particular you'll need HL SDK
version 2.3. You can find the original SDK 2.3 at the Valve Editing Resource Center (VERC),
and a modified version of SDK 2.3 at metmod.org/files/sdk.
Operation
The basic operation is, for each api call:
Note that each routine needs to set its META_RESULT value before returning. Plugin routines that do not set a value will be reported as errors in the logs.
Plugin coding requirements
Plugins must provide the following standard HLSDK exported function:
void GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals);
As well as the following new functions:
void Meta_Init(void); (optional) int Meta_Query(char *interfaceVersion, plugin_info_t **pinfo, mutil_funcs_t *pMetaUtilFuncs); int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs); int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason);
Also, it must provide at least one function returning a standard HL function table, from either the following standard HLSDK functions:
int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); int GetNewDLLFunctions( NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion );
or from the following new functions:
int GetEntityAPI_Post(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion); int GetEntityAPI2_Post(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ; int GetNewDLLFunctions_Post(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion); int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion); int GetEngineFunctions_Post(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion);
Thus, it needs to have (at least):
GiveFnptrsToDll Meta_Query Meta_Attach Meta_Detach <one or more Get function>
See the "stub_plugin" for an example of bare minimum code. See "trace_plugin" for an example of more complete functionality.
Also, if the plugin needs to use LINK_ENTITY_TO_CLASS, support for the particular entity(ies) has to be added explicitly to Metamod (linkfunc.cpp), just as it does for entities in game DLLs.
These are the valid META_RESULT values a plugin routine can specify:
Last, if any plugins specified META_OVERRIDE or META_SUPERCEDE, the return value given by the last such plugin is returned as the routine's return code to the engine (assuming a non-void routine). Thus, the order of the plugins as specified in the metamod.ini does have a possible effect.
Available Macros
The meta_api.h
header that describes the Metamod API functions, types, and structures also
includes several macros that can be of help when coding a plugin.
Utility Callback Functions
In version 1.05, Metamod began providing a set of utility functions to
plugins to centralize functionality, reduce code reuse, and to provide some
convenience in plugin coding. Presently, only a few functions are
provided. More are added as I find the time, and identify some advantage
to having them (either for my own plugins, or by others' request for their
plugins).
Note the PLID keyword passed to each function. This is basically a "plugin id" to indicate to Metamod which plugin is calling the function (else it's difficult to tell), and is a macro that should be specified verbatim with each call. (Currently, the macro is merely the plugin_info struct pointer returned by the plugin via Meta_Query; in the future this could change to some other identifier.)
L 04/17/2001 - 18:00:35: [TraceAPI] Tracing Engine routine 'RegUserMsg'
void LOG_ERROR(PLID, char *fmt, ...)
As in LOG_MESSAGE above, only marked as well with the
string "ERROR:". For example:
L 04/17/2001 - 18:03:13: [TraceAPI] ERROR: malloc failed
void LOG_DEVELOPER(PLID, char *fmt, ...)
As in LOG_MESSAGE above, only message will be logged only
if cvar developer is set to 1; message is marked as well with
the string "dev:". For example:
L 04/17/2001 - 18:03:13: [TraceAPI] dev: called: GiveFnptrsToDll
void CENTER_SAY(PLID, char *fmt, ...)
Prints a message on the center of all players' screens. This is
like the "centersay" of AdminMod, with pretty_say enabled, with the
same defaults (green, and a 10 second fade-in). A message is logged as
well, ie: [added in 1.06]
L 04/17/2001 - 15:44:52: [WDMISC] (centersay) random set up us the bomb!
void CENTER_SAY_PARMS(PLID, hudtextparms_t tparms, char *fmt, ...)
As in CENTER_SAY above, but allows specifying all the
parameters. (see SDK dlls/util.h for the struct
hudtextparms_t). [added in 1.06]
void CENTER_SAY_VARARGS(PLID, hudtextparms_t tparms, char *fmt, va_list ap)
As in CENTER_SAY_PARMS above, only the message is passed
as a vsnprintf style varargs format string and args list.
This is included merely because both the previous CENTER_SAY functions
actually call this, and it was convenient to include it as well.
[added in 1.06]
qboolean CALL_GAME_ENTITY(PLID, char *entStr, entvars_t *pev)
Calls an entity function in the gameDLL. For instance, a bot usually
needs to call the player entity function.
[added in 1.09]
int GET_USER_MSG_ID(PLID, const char *name, int *size)
Returns the id number corresponding to the given message name, of
those messages registered by the gamedll with RegUserMsg, optionally
returning the registered size of the message as well. This is to
allow things like bots to access the name/id mapping without having to
catch RegUserMsg themselves, and thus have to be loaded at startup.
[added in 1.11]
const char * GET_USER_MSG_NAME(PLID, int msgid, int *size)
Returns the name corresponding to the given msgid number, of those
messages registered by the gamedll with RegUserMsg, optionally
returning the registered size of the message as well. It will return
guess-names for any builtin Engine messages that it knows about
(SVC_TEMPENTITY, etc). The returned string is presumed to be
a compile-time constant string, stored in the text segment of the
gamedll.
[added in 1.11]
const char * GET_PLUGIN_PATH(PLID)
Returns the full pathname of the loaded dll/so file for the calling
plugin. The returned string is a pointer to a static buffer, and should be
copied by the caller to local storage.
[added in 1.12]
const char * GET_GAME_INFO(PLID, ginfo_t type)
Returns various string-based information about the running
game/MOD/gamedll. The given type can be one of:
Plugin Loading
(this is some rough notes I intend to fill in in the future)
Plugins are loaded when the engine calls GiveFnptrsToDll(). The config file is parsed, and for each valid plugin (uncommented, platform relevant), the operation is:
Meta_Init (if present) GiveFnptrsToDll Meta_Query Meta_Attach
GetEntityAPI GetEntityAPI2 GetNewDLLFunctions GetEntityAPI_Post GetEntityAPI2_Post GetNewDLLFunctions_Post GetEngineFunctions GetEngineFunctions_Post