<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.alliedmods.net/index.php?action=history&amp;feed=atom&amp;title=Talk%3AIntroduction_to_sourceMod_Plugins</id>
	<title>Talk:Introduction to sourceMod Plugins - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.alliedmods.net/index.php?action=history&amp;feed=atom&amp;title=Talk%3AIntroduction_to_sourceMod_Plugins"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Introduction_to_sourceMod_Plugins&amp;action=history"/>
	<updated>2026-04-06T14:46:10Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Introduction_to_sourceMod_Plugins&amp;diff=8882&amp;oldid=prev</id>
		<title>Asherkin: Created page with &quot; ----  &lt;div class=&quot;info&quot;&gt;Below is FaTony's WIP rewrite of the command tutorial, it's been remove from the main page as it's incomplete and more confusing for new users&lt;br&gt;--~~...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Introduction_to_sourceMod_Plugins&amp;diff=8882&amp;oldid=prev"/>
		<updated>2013-03-17T16:12:18Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot; ----  &amp;lt;div class=&amp;quot;info&amp;quot;&amp;gt;Below is FaTony&amp;#039;s WIP rewrite of the command tutorial, it&amp;#039;s been remove from the main page as it&amp;#039;s incomplete and more confusing for new users&amp;lt;br&amp;gt;--~~...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;info&amp;quot;&amp;gt;Below is FaTony's WIP rewrite of the command tutorial, it's been remove from the main page as it's incomplete and more confusing for new users&amp;lt;br&amp;gt;--[[User:Asherkin|Asherkin]] ([[User talk:Asherkin|talk]]) 11:12, 17 March 2013 (CDT)&amp;lt;/div&amp;gt;&lt;br /&gt;
=Creating client command=&lt;br /&gt;
So far we have learned how to set up our plugin and run some code. But our plugin still doesn't do anything useful. Let's add a console command to allow clients to see their kills/deaths ratio. For demonstration purposes, we are going to start with very naive implementation that a beginner could write, then we'll look at the common bugs it contains, fix them and add more advanced features. In the end we'll have a mature feature-rich implementation and experience that will prevent us from making simple mistakes in the future.&lt;br /&gt;
&lt;br /&gt;
==Naive implementation==&lt;br /&gt;
First, we need to register our console command. &amp;lt;tt&amp;gt;OnPluginStart&amp;lt;/tt&amp;gt; is a good place to do that. In order to register our console command, we need to use &amp;lt;tt&amp;gt;RegConsoleCmd&amp;lt;/tt&amp;gt; function, it is declared inside '''console.inc''', here's how it's declared:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Creates a console command, or hooks an already existing one.&lt;br /&gt;
 *&lt;br /&gt;
 * Console commands are case sensitive.  However, if the command already exists in the game, &lt;br /&gt;
 * the a client may enter the command in any case.  SourceMod corrects for this automatically, &lt;br /&gt;
 * and you should only hook the &amp;quot;real&amp;quot; version of the command.&lt;br /&gt;
 *&lt;br /&gt;
 * @param cmd			Name of the command to hook or create.&lt;br /&gt;
 * @param callback		A function to use as a callback for when the command is invoked.&lt;br /&gt;
 * @param description	Optional description to use for command creation.&lt;br /&gt;
 * @param flags			Optional flags to use for command creation.&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error				Command name is the same as an existing convar.&lt;br /&gt;
 */&lt;br /&gt;
native RegConsoleCmd(const String:cmd[], ConCmd:callback, const String:description[]=&amp;quot;&amp;quot;, flags=0);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This native looks a bit more complicated than the previous one, so let's go through each argument step by step. First one is the name of our command, we'll use &amp;lt;tt&amp;gt;&amp;quot;sm_kdr&amp;quot;&amp;lt;/tt&amp;gt;. Second one is a callback, but it has unknown tag &amp;lt;tt&amp;gt;ConCmd&amp;lt;/tt&amp;gt;. In order to correctly call &amp;lt;tt&amp;gt;RegConsoleCmd&amp;lt;/tt&amp;gt; we need to find how &amp;lt;tt&amp;gt;ConCmd&amp;lt;/tt&amp;gt; is declared. Thankfully, we don't need to look hard, it's declared right above &amp;lt;tt&amp;gt;RegConsoleCmd&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Called when a generic console command is invoked.&lt;br /&gt;
 *&lt;br /&gt;
 * @param client		Index of the client, or 0 from the server.&lt;br /&gt;
 * @param args			Number of arguments that were in the argument string.&lt;br /&gt;
 * @return				An Action value.  Not handling the command&lt;br /&gt;
 *						means that Source will report it as &amp;quot;not found.&amp;quot;&lt;br /&gt;
 */&lt;br /&gt;
functag public Action:ConCmd(client, args);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This is a function tag. What does it mean? It means that we need to define our own function that will have the same prototype (number of arguments, their tags and return tag) as the one of function tag. However, in this case, we don't need to (and can't) use the same name as in tag, that would result in error. We need to use our own name, let's use &amp;lt;tt&amp;gt;Command_KDR&amp;lt;/tt&amp;gt;. Function tags doesn't require to use the same argument names as specified in declaration, but it's a good idea to use them, because they usually have the most meaning. So, all in all, it leads us to the following definition:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public Action:Command_KDR(client, args)&lt;br /&gt;
{&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Now, if you've been following carefully, you should see that we have another unknown tag here - &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt;. Let's look how it's declared ('''core.inc'''):&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Specifies what to do after a hook completes.&lt;br /&gt;
 */&lt;br /&gt;
enum Action&lt;br /&gt;
{&lt;br /&gt;
	Plugin_Continue = 0,	/**&amp;lt; Continue with the original action */&lt;br /&gt;
	Plugin_Changed = 1,		/**&amp;lt; Inputs or outputs have been overridden with new values */&lt;br /&gt;
	Plugin_Handled = 3,		/**&amp;lt; Handle the action at the end (don't call it) */&lt;br /&gt;
	Plugin_Stop = 4,		/**&amp;lt; Immediately stop the hook chain and handle the original */&lt;br /&gt;
};&amp;lt;/pawn&amp;gt;&lt;br /&gt;
It's an enumeration tag and in our callback it's up to us to decide which value to return. As you probably understood from reading all the info, SourceMod console commands are implemented as hooks between client and original server code. If we don't return anything and &amp;quot;let it slide&amp;quot; or return &amp;lt;tt&amp;gt;Plugin_Continue&amp;lt;/tt&amp;gt;, the original command from client will reach the server and, since it's highly unlikely that there is &amp;lt;tt&amp;gt;sm_kdr&amp;lt;/tt&amp;gt; command in the game, the message &amp;lt;tt&amp;gt;Unknown command &amp;quot;sm_kdr&amp;quot;&amp;lt;/tt&amp;gt; will be printed to client's console. We don't want that, so let's modify our callback to return &amp;lt;tt&amp;gt;Plugin_Handled&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public Action:Command_KDR(client, args)&lt;br /&gt;
{&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
It's a very common mistake to forget to return &amp;lt;tt&amp;gt;Plugin_Handled&amp;lt;/tt&amp;gt; so our naive implementation is going to be not so naive after all! Now, after we finally understood how &amp;lt;tt&amp;gt;ConCmd&amp;lt;/tt&amp;gt; tag works, it's time to move to the next argument of &amp;lt;tt&amp;gt;RegConsoleCmd&amp;lt;/tt&amp;gt;. It is a string that will act like a description of our command. However, notice the &amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt; after argument name, it indicates that this argument is optional, we can skip it and empty string (&amp;lt;tt&amp;gt;&amp;quot;&amp;quot;&amp;lt;/tt&amp;gt;) will be used. And the last argument is flags and it's also optional. Command flags are used to change behavior of command, but for now default behavior is ok. Now we know the meaning of all arguments, let's make a call.&lt;br /&gt;
&amp;lt;pawn&amp;gt;RegConsoleCmd(&amp;quot;sm_kdr&amp;quot;, Command_KDR, &amp;quot;Displays the client their kills/deaths ratio.&amp;quot;);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Notice that we skipped flags because we want default behavior. Now let's see how the full command-related code looks like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;sm_kdr&amp;quot;, Command_KDR, &amp;quot;Displays the client their kills/deaths ratio.&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Command_KDR(client, args)&lt;br /&gt;
{&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Why did we choose &amp;lt;tt&amp;gt;sm_kdr&amp;lt;/tt&amp;gt; as the name of our command? It's handy because it will create convenient [[Commands_%28SourceMod_Scripting%29#Chat_Triggers|chat triggers]]. The skeleton of our command is ready, it is time to write the actual code for calculating KDR and displaying it to client. Notice that the first argument of our &amp;lt;tt&amp;gt;Command_KDR&amp;lt;/tt&amp;gt; callback is &amp;lt;tt&amp;gt;client&amp;lt;/tt&amp;gt;. When our callback is called, it will hold the index of client who called our command. We'll use this to find necessary information about client and to display that information back. First, let's find the number of kills, we'll use &amp;lt;tt&amp;gt;GetClientFrags&amp;lt;/tt&amp;gt; function for that, it's declared in '''clients.inc''':&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Returns the client's frag count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param client		Player's index.&lt;br /&gt;
 * @return				Frag count.&lt;br /&gt;
 * @error				Invalid client index, client not in game, or no mod support.&lt;br /&gt;
 */&lt;br /&gt;
native GetClientFrags(client);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
It takes one argument - the client index and returns the number of frags. For the only argument of &amp;lt;tt&amp;gt;GetClientFrags&amp;lt;/tt&amp;gt; we'll use &amp;lt;tt&amp;gt;client&amp;lt;/tt&amp;gt; argument of our callback and we also need to store the return value so we'll create a local variable for that:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new kills = GetClientFrags(client);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
By this time, it is assumed that you've learned how to read include files and find necessary information, so only links to online SourceMod API will be provided. Next, we need to find the number of client deaths, we'll use &amp;lt;tt&amp;gt;[http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=431&amp;amp; GetClientDeaths]&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new deaths = GetClientDeaths(client);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Now that we have both kills and deaths, let's find the ratio. Remember that by default all variables in SourcePawn act like integers, but we need the fractional part in this case. Another very important thing to remember is that a result of integer division is also an integer. So we need to convert both kills and deaths to floating point values and store the result in a floating point variable. &amp;lt;tt&amp;gt;[http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=705&amp;amp; float]&amp;lt;/tt&amp;gt; function does the conversion.&lt;br /&gt;
&amp;lt;pawn&amp;gt;new Float:ratio = float(kills) / float(deaths);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
And now we only need to display the ratio, since our command can be called either via console or chat, it is good idea to display our info accordingly, so we'll use &amp;lt;tt&amp;gt;[http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=462&amp;amp; ReplyToCommand]&amp;lt;/tt&amp;gt;. It's another [[Format_Class_Functions_(SourceMod_Scripting)|format class function]] and now we need to apply some formatting. In a nutshell, we pass the string which acts as a template for text and &amp;lt;tt&amp;gt;%&amp;lt;/tt&amp;gt; sign and one-letter type identifier (which is called format specifier) for variable values to put inside that template. After that, we must pass the number of arguments that correspond to the number of format specifiers in our format string. Since we have a floating point number, the format specifier will be &amp;lt;tt&amp;gt;%f&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pawn&amp;gt;ReplyToCommand(client, &amp;quot;Your KDR is: %f.&amp;quot;, ratio);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
That's it! Now let's see the full code of our naive implementation:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public Plugin:myinfo =&lt;br /&gt;
{&lt;br /&gt;
	name = &amp;quot;My First Plugin&amp;quot;,&lt;br /&gt;
	author = &amp;quot;Me&amp;quot;,&lt;br /&gt;
	description = &amp;quot;My first plugin ever&amp;quot;,&lt;br /&gt;
	version = &amp;quot;1.0&amp;quot;,&lt;br /&gt;
	url = &amp;quot;http://www.sourcemod.net/&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;sm_kdr&amp;quot;, Command_KDR, &amp;quot;Displays the client their kills/deaths ratio.&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Command_KDR(client, args)&lt;br /&gt;
{&lt;br /&gt;
	new kills = GetClientFrags(client);&lt;br /&gt;
	new deaths = GetClientDeaths(client);&lt;br /&gt;
	new Float:ratio = float(kills) / float(deaths);&lt;br /&gt;
	ReplyToCommand(client, &amp;quot;Your KDR is: %f.&amp;quot;, ratio);&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Compile and test this plugin and notice that something is wrong. We'll talk about it in the next section.&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Asherkin</name></author>
		
	</entry>
</feed>