Coding for Metamod


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 metamod.org/files/sdk.


Operation

The basic operation is, for each api call: Also, for any api call, each plugin has the opportunity to replace the real routine, in two ways: Thus after each plugin is called, its META_RESULT 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: These aren't used by Metamod itself, but could be used by plugins to get an idea if a previous plugin did anything.

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.


Operation Details

These are the valid META_RESULT values a plugin routine can specify:

As the plugins are called, a running status is kept of the "highest" meta status so far, in the order (lowest to highets) shown above. After calling all the "normal" routines, the status is checked to see if the gameDLL's routine should be called - ie, it will not be called if one (or more) of the plugin's has specified META_SUPERCEDE. The gameDLL's routine is then called, or skipped, as appropriate. Then, all the "post" routines are called in the same manner (except META_SUPERCEDE is no longer a valid meta result).

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.)


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: