This guide will give you a basic introduction to writing a [[SourceMod]] plugin. If you are not familiar with the SourcePawn language, it is recommended that you at least briefly read the [[Introduction to SourcePawn]] article.

This guide will give you a basic introduction to writing a [[SourceMod]] plugin. If you are not familiar with the SourcePawn language, it is recommended that you at least briefly read the [[Introduction to SourcePawn]] article.

Open your favorite text editor and create a new empty file. When youhavean empty file you can just start writing code usingthecore language, however, you will not be able to use any of SourceMod features because the compiler does not now about them. This is done deliberately so it is possible to use SourcePawn outside of SourceMod. But since we are writing a SourceMod plugin, it is a good idea to enable access to SourceMod features first. This it done using #include directive. It tells compiler to "paste" the code from another file into yours.

−

*'''Includes''' -Allowsyou toaccessthe SourceModAPI,and if you desire, APIs from externalSourceModextensionsandplugins.

+

#include

−

*'''Info'''- Public information aboutyourplugin.

+

How does this work? First of all, note that we enclosed file name into angle brackets. Angle brackets tell the compiler to look in the default include directory. By default, it is'''scripting/include'''. You can open it right now and see a lot of inc files there. Those are SourceMod include files that describe various functions, tags and other features available for SourceMod plugins. The files are plain-text andyouare encouragedtoread them. You will notice however, that there's not much code in there, certainly not enough to implement allthegreat features ofSourceMod,so where are they? They are implemented inside aSourceModcore which is written in C++andis compiled into binary files which end up in'''bin'''directory. So how doesyourSourcePawn code and SM core link together if compiler doesn't know about existence of the latter? SourceMod include files are written specially, so they say that the implementation of functions is''somewhere else''. Compiler understands that and generate a special code that says that thisfunctioncall is going outside. When SourceMod loadsyour plugin, it inspects these bits of code and substitutes it's own internal functions instead. This is called [http://en.wikipedia.org/wiki/Dynamic_linking dynamic linking].

Now that we got access to SourceMod features, it is time to setup the information that will be displayed via sm plugins list command. No one likes unnamed plugins. To do that we are going to look inside '''sourcemod.inc''' file and see the format that information should be declared. It's always helpful to look inside SM include files to find out information you don't know. There is also an [http://docs.sourcemod.net/api/ API documentation] but it can be outdated and it only has SM core files so if your plugin are going to use any third party extension or another plugin, you will have to study inc files. So, open '''sourcemod.inc''' and scroll down a bit until you seethis:

−

#include

+

/**

+

* Plugin public information.

+

*/

+

struct Plugin

+

{

+

const String:name[], /**

+

const String:description[], /**

+

const String:author[], /**

+

const String:version[], /**

+

const String:url[], /**

+

};

+

and this:

+

/**

+

* Declare this as a struct in your plugin to expose its information.

+

* Example:

+

*

+

* public Plugin:myinfo =

+

* {

+

* name = "My Plugin",

+

* //etc

+

* };

+

*/

+

public Plugin:myinfo;

+

+

It tells us that we need to create a global public variable myinfo which must be of type Plugin which is a struct with 5 fields which themselves are strings. It may sound complicated for a beginner but it's easy. Let's go ahead and create one:

+

public Plugin:myinfo =

+

{

+

name = "My First Plugin",

+

author = "Me",

+

description = "My first plugin ever",

+

version = "1.0",

+

url = "http://www.sourcemod.net/"

+

};

+

+

The public keyword means that SourceMod will be able to directly access our variable. Plugin: defines a type of our variable. myinfo is, obviously, a name of our variable as required by SourceMod. You see that we initialize it right away. This is preferred way to do when filling out plugin info.

+

+

After that the full code of your plugin should look like this:

+

#include

public Plugin:myinfo =

public Plugin:myinfo =

Line 18:

Line 54:

author = "Me",

author = "Me",

description = "My first plugin ever",

description = "My first plugin ever",

−

version = "1.0.0.0",

+

version = "1.0",

+

url = "http://www.sourcemod.net/"

+

};

+

+

=Getting code to run=

+

We already include SourceMod features and filled up or plugin info. We now have a perfectly well formed plugin which can be compiled and loaded by SourceMod. However, there is one problem - it does nothing. You might be tempted to just start writing a code after myinfo declaration just to see that it will not compile. SourcePawn, unlike other scripting languages like Lua, does not allow a code to be outside of functions. After reading that, you may probably want to just define some function, name it main probably, compile and load a plugin and see that your code never gets called. So how do we make SourceMod call our code? For this exact reason we have forwards. Forwards are function prototypes declared by one party that can be implemented by another party. When a first party starts a forward call, all parties that implemented that forward receive the call. SourceMod declares a plenty of interesting forwards that we can implement. As you can see, forwards are the only way to get our code executed, keep that in mind. So let's implement OnPluginStart forward. As you may have guessed, it is called when our plugin starts. To do that, we'll have to look up the declaration of OnPluginStart. It is declared inside '''sourcemod.inc''', a file we are already familiar with, let's find it:

+

/**

+

* Called when the plugin is fully initialized and all known external references

+

* are resolved. This is only called once in the lifetime of the plugin, and is

+

* paired with OnPluginEnd().

+

*

+

* If any run-time error is thrown during this callback, the plugin will be marked

+

* as failed.

+

*

+

* It is not necessary to close any handles or remove hooks in this function.

Empty parentheses tells us that no arguments are passed inside this forward, @noreturn inside documentation tells us that we don't have to return anything, pretty simple forward. So how to implement it? Firstly, our implementation must have the same name, so it's OnPluginStart, secondly, our implementation should have the same number of arguments, none in this case, and lastly, SourceMod needs to be able to call our implementation so it needs to be public. So the implementation looks like this:

+

public OnPluginStart()

+

{

+

}

+

+

Now we can write code inside curly braces and it will be executed when our plugin starts. Let's output "Hello world!" to server console. To do that we are going to use PrintToServer function. It is declared inside '''console.inc''', however, we don't need to manually include '''console.inc''' because it is included automatically as part of '''sourcemod.inc'''.

+

/**

+

* Sends a message to the server console.

+

*

+

* @param format Formatting rules.

+

* @param ... Variable number of format parameters.

+

* @noreturn

+

*/

+

native PrintToServer(const String:format[], any:...);

+

As you can see, this is a native function. It is implemented inside SM core. Judging by it's arguments, we can see that it is a [[Format_Class_Functions_%28SourceMod_Scripting%29|format class function]]. However, we don't need any formatting right now, so let's just pass "Hello world!" string as an only argument:

The information portion is a special syntax construct. You cannot change any of the keywords, or the public Plugin:myinfo declaration. The best idea is to copyandpaste this skeletal structureandmodifythestrings to get started.