Classic framework
Very early version, many mistakes indeed.
This document deals with framework for Half-life 1 plugin (e.g. bot) running without Metamod. There is also document about framework using metamod.
This document is good for understanding structure of a plugin. It describes connections between the Half-Life, 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.
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
click above for Classic framework diagram, the most important part of this document. (82911 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
Middle column : bot
Middle column represents your plugin. It sits between Half-Life engine and Game. To achieve this, you must point to your plugins library in Games liblist.gam file, replacing pointer to Games library.
Right column : Game
Game is Half-Life deathmatch or any other mod (e.g. Counter-Strike)
Other
- Arrows symbolizes that some block/function is calling other function.
- 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.
1 - Exported functions
These functions are exported from your plugin / Game, and are called by Half-Life at the start of the game. They estabilish connection between Half-Life, your plugin and Game (mod). They are all called only once.
1a
These are functions you must provide for Half-Life, thus you must export them.
- GiveFnptrsToDll() - This is the first function that will be called in your library. Half-Life engine will send you global variables [3] and pointer to all engine functions [4a]. You must call mods GiveFnptrsToDll() with pointer to your fake engine functions [4b] to successfully hook them.
- GetEntityAPI() - This is same as GetEntityAPI2(), only less safe. Use GetEntityAPI2() instead.
- GetEntityAPI2() - Half-life engine is requesting game API functions here. So you first call GetEntityAPI2() in the mod (or call GetEntityAPI if mod does not have GetEntityAPI2 exported) to get game API functions [6b]. Then you will replace these functions with your own fake game API functions [6a], and again you have total control over gameAPI functions
- GetNewDLLFunctions() - Similar to GetEntityAPI2(), but requesting game New API functions. Call mods GetNewDLLFunctions, obtain game New API [5b] and return changed fake game New API functions [5a].
- Server_GetBlendingInterface() - You only have to call mods Server_GetBlendingInterface() so you don't break connection.
1b
Because you are sitting between Half-Life and Game (mod), you must both act as mod and Half-Life engine. So you must manually load mods library and call all these functions by yourself.
You will call these functions from your plugin, giving and requesting vital informations. See section 1a for more info.
2 - Entities
Because you must look exactly like the mod you are going to hook, you must export every function which is exported from the mod (Game). You have already exported some functions [1a], but it is not enough. These other functions you export [2a] are just calling real functions in mod [2b]. They vary from mod to mod and you can get them by examining mods dll, or search in this list
3 - Global variables
You acquire pointer to engines global variables in GiveFnptrsToDll(). Your plugin must also send this pointer to mod, by calling its GiveFnptrsToDll(). This 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 must also give those or your fake [4b] functions to mod (Game) by calling its GiveFnptrsToDll()
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.
Note that not all engine functions [4a] must be replaced by our fake functions [4b]. Functions in which we are not interested should be passed directly to mod, so number of our fake engine functions is ususally lower than real engine functions.
4b
Our fake engine functions will be called by mod (Game) when it wants to call Half-lifes functions. We do our stuff and after that, we should call real engine functions [4a] with help of our pEngineFunctionsFromEngine pointer.
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.
Be aware that mod (Game) may not return all game (new) API functions [5b, 6b], so you should not replace every possible function by your own fake version [5a, 6a]
See list of all game API and game newAPI functions
5a, 6a
We pass these functions to Half-Life in GetEntityAPI()/GetNewDLLFunctions(). All of our fake (new)API functions should call real mod (new)API functions [5b, 6b] with the help of the pGameAPI/pGameNewAPI pointers.
Note that not all game (new) API functions [5b, 6b] must be replaced by our fake functions [5a, 6a]. Functions in which we are not interested should be passed directly to Half-Life, so number of our fake (new) API functions is ususally lower than real game (new) API functions.
5b, 6b
We store game (new) API functions in our pGameAPI/pGameNewAPI pointers. We can call them anytime, and we shall also call them from within our fake game (new) API functions [5a, 6a], completing the loop