Sample Plugins (Metamod:Source)
Metamod:Source comes with two sample plugins: stub and sample. This article is a brief overview of how to read and compile them. They are intended as a baseline for developing your own plugins, though they are certainly not required for your own development.
Metamod:Source is a C++ environment, but this is not a C++ tutorial. You should have sufficient knowledge of computer organization (memory, pointers, addressing) and intermediate experience with C++. Most importantly, you should be willing to dive into header files to research API definitions (which is necessary for the HL2SDK regardless).
Contents
Introduction
Before you begin, you should set up your Metamod:Source Environment. If you fail to complete this step, it is unlikely much else in this article will work for you.
The two sample plugins provided are:
- stub_mm - Bare-bones plugin that does almost nothing.
- sample_mm - More complete example plugin which implements a few things that Valve's serverplugin_sample does, such as hooking functions, creating ConVars, console commands, and showing dialog boxes.
The Engine Divide
The Orange Box and Episode 1 engines are not compatible, and thus there is a division:
- Metamod:Source 1.4/Episode 1
- Metamod:Source 1.6/Orange Box
Unfortunately, there is a "lag period" where not all games have moved to the new engine. It is likely that this lag period will continue for at least another twelve months (this writing is as of February 2008). As such, we are writing all of our plugin code such that it compiles against both platforms. It is your choice whether to do this as well. As the usage of Metamod:Source 1.4 and the original engine decays, we will begin removing the legacy cruft from the sample plugins. That probably won't happen until Valve has a stable port of CS:S to Orange Box.
As such, you will notice various idiosyncracies in the sample plugins. For example, METAMOD_PLAPI_VERSION exists in Metamod:Source 1.6 or later, so it is used to decide between GetEngineFactory (1.6) or engineFactory (1.4). Similarly, the sample plugins use two macros:
- ENGINE_ORANGEBOX - Orange Box build
- ENGINE_ORIGINAL - Original/Episode 1 build
These two macros are used in a few places to toggle functionality compatible for the given build.
For more information, see:
Compiling
Windows
Both plugins have a Visual Studio 2005 project file in their msvc8 folders. Each plugin has four build modes:
- Release - Orange Box - Release mode, Orange Box, MM:S 1.6
- Debug - Orange Box - Debug mode, Orange Box, MM:S 1.6
- Release - Original - Release mode, Original/Episode1, MM:S 1.4
- Debug - Original - Debug mode, Original/Episode1, MM:S 1.4
There exists normal "Release" and "Debug" build modes -- you should not use them, as they are not configured.
Linux
On Linux, you cannot simply type "make" in the folder containing the Makefile. You must specify a combination of parameters:
- ENGINE - Required. Must be either "orangebox" or "original".
- DEBUG - Optional. Can be empty (Release mode) or "true" (Debug mode).
Binaries and object files will be written to one of the following folders:
- Release.orangebox
- Debug.orangebox
- Release.original
- Debug.original
Examples of building one of the example plugins:
#MM:S 1.4/Episode 1, debug mode make DEBUG=true ENGINE=original #MM:S 1.6/Orange Box, release mode make ENGINE=orangebox #Cleaning the MM:S 1.4 build make clean ENGINE=original
Note that you may need to edit the folder locations at the top of the Makefile, in case you set up your paths differently.
Stub Plugin
The stub plugin is a very simple, bare-bones plugin. It has little, if anything, beyond an implementation of the required API callbacks.
It hooks one function, IServerGameDLL::ServerActivate, which is a callback fired after IServerGameDLL::LevelInit.
Note that for the most part, stub_mm is free of compatibility cruft, whereas sample_mm tries to abstract more. This is so stub_mm doesn't appear to be "hiding" anything -- it's laid out very simply.
Sample Plugin
The full sample plugin is a bit more complicated, as it contains some of the examples from Valve's serverplugin_sample. It also may be a bit messy to read because of the engine compatibility wrappers in it.
The first file of importance is engine_wrappers.h, which is full of compatibility shims. For example:
- engineFactory became GetEngineFactory from 1.4 to 1.6
- serverFactory became GetServerFactory from 1.4 to 1.6
- ISmmAPI::Format did not exist in 1.4, so we created a simple #define to use snprintf instead. You could also use Valve's Q_snprintf if you desired.
- Valve renamed VENGINE_CVAR_INTERFACE_VERSION to CVAR_INTERFACE_VERSION from Episode 1 to Orange Box.
- The syntax to SH_CALL changed from 1.4 to 1.6 (which we have demonstrated for completeness and will be explained later).
Also note the CCommand class. This is a wrapper around the IVEngineServer::Cmd_Arg* functions, which were removed in Orange Box. Valve replaced it with a newer, more re-entrant set of functions based around CCommand. Rather than create two codebases, we've simply wrapped the old functions in the new API. The functionality isn't exactly the same (becaose of re-entrancy), but it works nicely for our purposes. You can read more about this trick in Porting to Orange Box.
The VDF Files
Note that both stub_mm and sample_mm come with their own VDF files. These are example files that load their respective binaries from the addons folder. Make two notes about this:
- VDF files go in Metamod's folder. That is, addons/metamod (or whatever mm_basedir is). They are not Valve Server Plugin files and they cannot go in the addons folder.
- If your plugin has more than one file, or it creates other files, it may be prudent to place it in its own sub-folder. The sample plugins are small and thus we placed the binaries in addons for simplicity. The extended convention for more complicated plugins is:
- addons/NAME/bin/NAME_mm.dll or addons/NAME/bin/NAME_mm_i486.so. For example, addons/sourcemod/bin/sourcemod_mm is SourceMod's VDF path, since it has a large directory structure.
- Note: This convention is not required, but it is recommended.