Metamod framework

Very early version, many mistakes indeed.

This document deals with framework for Half-life 1 plugin (e.g. bot) running with Metamod. There is also document about classic framework.

This document is good for understanding structure of a plugin. It describes connections between the Half-Life, metamod, game and plugin. It deals with exported functions, game API and engine API. It shows how these functions are called and how they cooperate. It also helps If you're lost in all these calls and hooks.

For more information about writing a plugin for Half-Life and how it works, see Botmans page or Bots united.

It is recommended that you are familiar with classic framework.

Newest version of this document will be found on http://neuron.tuke.sk/~wagner someday

Copyright © 2005 Jozef Wagner, http://neuron.tuke.sk/~wagner

Diagram

Metamod framework

click above for Metamod framework diagram, the most important part of this document. (104786 bytes)

Description

Left column : Half-Life 1 engine

This represents Half-life engine, which starts when you run the game. After some initialization stuff, Half-Life engine will run a game, specified by -game parameter in command line or by choosing one in game

Top column : Metamod

Metamod is third party Half-Life plugin, which sits between Half-Life and mod (Game). It also loads and calls other (and your) plugins. This way you do not have to call mod (Game) yourself.

Right column : bot

Right column represents your plugin. It is initialized and called by Metamod. You must modify plugin.ini in metamods directory, persuading metamod to call your plugin. Note that there may be other plugins just like yours which are called by metamod.

Bottom column : Game

Game is Half-Life deathmatch or any other mod (e.g. Counter-Strike)

Other

  • Green rectangles means that given function must be exported from library.
  • Full circles symbolizes functions which can be called. They are not exported, but their presence was given away some other way.
  • Green full circles in your plugin are functions called before actual real function (engine or game (new) API) is called
  • Blue full circles in your plugin are functions called after actual real function (engine or game (new) API) is called. You can make use of MetamodGlobals here, where return value from real function is stored.

1 - Initialization

Note that contrary to classic framework, you must not load mod (Game) library yourself, or call its exported functions from your own. Metamod will take care of all those things for you.

You also don't change liblist.gam file, which should point to metamod. Instead you must add reference to your plugin in Metamods plugin.ini file

1a

These functions are exported from your plugin, and are called by Metamod. They are all called only once.

  • Meta_Init() - First function called. Its purpose is only to tell your plugin that it is running under metamod. You don't have to export this function.
  • Meta_Query() - This function will give you pointer to Metamod Utility Functions [2a]. Also you must set pluginInfoPointer here, in which you specify some vital informationas about your plugin, such as plugins name, version, authors name, and information about when Metamod is allowed to (un)load your plugin.
  • Meta_Attach() - Called when metamod is loading your plugin. Pointers to Mod (Game) API [6b] and mod (Game) newAPI [5b] functions are given here for your plugin. This function also gives you a pointer to MetaGlobals variables [2b]. One more important thing you must do here is to fill given functionsTable pointer with pointers to your other initialization functions, [1b] and [1c]
  • Meta_Detach() - Is called when metamod unloads your plugin.
  • GiveFnptrsToDll() - This is the second function that will be called in your library. Half-Life engine will send you global variables [3] and pointer to all engine functions [4a].

1b

You are hooking your fake mod (Game) API/newAPI and fake engine functions here.

Contrary to plugin examples in metamod, you do not have to export these functions.

Note that you don't have to provide all of these functions. However, you must provide one at least.

  • GetEntityAPI() - This is same as GetEntityAPI2(), only less safe. Use GetEntityAPI2() instead.
  • GetEntityAPI2() - Metamod is requesting fake API functions here. Set pointer to your fake API functions here [6a]. You don't have to hook every function.
  • GetNewDLLFunctions() - Similar to GetEntityAPI2(), but requesting fake New API functions [5a].
  • GetEngineFunctions() - You can hook engine functions here [4b]. If mod wants to call engine function, your hooked function will be called first and then actual engine function will be called.

You must send pointers to these functions in Meta_Attach()

1c

These functions are somewhat similar to [1b]. You will initialize all your fake _Post functions here. [4c, 5c, 6c]

_Post functions will be called after actual real function finishes. See "example of half-life calling game function" arrows in diagram

Contrary to plugin examples in metamod, you do not have to export these functions.

You must send pointers to these functions in Meta_Attach()

Note that you don't have to provide all of these functions.

2 - Metamod specific

Metamod is taking care of correct communication between Half-Life, mod (Game), and attached plugins. That's right, your plugin does not have to be only one loaded.

2a

pMetamodUtilityFuncitons points to many helpful Metamod utility functions. You can call them from your plugin. See Utility Callback Functions section for more info.

You will acquire pointer to these functions in Meta_Query()

2b

Metamod Global variables stores vital information for your plugin, such as return value from real engine function.

You will acquire pointer to these variables in Meta_Attach()

3 - Global variables

You acquire pointer to engines global variables in GiveFnptrsToDll(). These variables store some vital information, for example :

  • actual game time
  • trace result
  • map name
  • vectors from Angle-to-Vector conversion

You can (and presumably will) use these variables anytime/anywhere in your mod

4 - Engine Functions

Engine functions [4a] are given to your plugin in GiveFnptrsToDll(). You provide your fake engine functions [4b] in GetEngineFunctions() and _Post engine functions [4c] in GetEngineFunctions_Post(). You don't have to hook every function.

See list of all engine functions

4a

Pointer pEngineFunctionsFromEngine points to Half-life engine functions [4a], and it is used whenever we need to call engine function.

4b, 4c

Your fake engine functions will be called by Metamod when mod (Game) wants to call Half-lifes functions.

When mod (Game) wants to call some engine function, this is what metamod will call :

  1. Your fake function from [4b]. We can tell metamod not to call real engine function here by changing some value in [2b]
  2. real engine function, [4a]
  3. Your fake _Post function from [4c]. Return value from real engine function is in [2b]

You don't have to call engine functions from your faked ones most of time. Metamod will take care of it

You must set correct return value in [2b] every time your function is called. Valid values are MRES_IGNORED and MRES_HANDLED (plus MRES_OVERRIDE and MRES_SUPERCEDE for [4b])

5, 6 - mod API (mod New API)

Note that separating game API into 2 sets (API and newAPI) is caused by evolution of Half-Life. There were some new functions Half-life needed to call in mod, so instead of changing actual API interface, Valve created new interface, called newAPI. These two interfaces are similar, they only call different functions.

You don't have to hook every function.

See list of all game API functions

See list of all game newAPI functions

5a, 6a

You've passed these functions to Half-Life in GetEntityAPI()/GetNewDLLFunctions().

5b, 6b

We store game (new) API functions given in Meta_Attach() in our pGameAPI/pGameNewAPI pointers. You can call them anytime.

You must set correct return value in [2b] every time your function is called. Valid values are MRES_IGNORED, MRES_HANDLED, MRES_OVERRIDE and MRES_SUPERCEDE

5c, 6c

Your _Post API functions will be called after real API functions end. For better understanding, see section [4] and example of Half-Life calling mod API function in the diagram

You must set correct return value in [2b] every time your function is called. Valid values are MRES_IGNORED and MRES_HANDLED