Scripting FAQ (SourceMod)
Contents
- 1 How do I learn SourcePawn?
- 2 Where can I find all the SourcePawn functions and other information?
- 3 How do I find the classname of an entity? (e.g., "weapon_knife" or "prop_physics")
- 4 How do I block regular commands, such as kill and say?
- 5 How do I hook +commands, such as +zoom and +attack?
- 6 How do I get rid of loose indentation warnings?
- 7 How do I get rid of tag mismatch warnings?
How do I learn SourcePawn?
A good start is on the Introduction to SourcePawn page, which will teach you the SourcePawn language. Then go through the Introduction to SourceMod Plugins, which will teach you how to write your first plug-in.
Where can I find all the SourcePawn functions and other information?
All SourceMod plug-ins have this line:
#include <sourcemod>
This line instructs the compiler to retrieve the file sourcemod.inc from the sourcemod/scripting/include folder. Every function, variable, and definition can be found in the .inc files inside the sourcemod/scripting/include folder.
But searching through all those files can be quite tedious. Thankfully, the honourable Nican created an API reference viewable on the web, complete with searching and commenting: http://docs.sourcemod.net/api/
Also, if you are in the SourceMod IRC channel (#sourcemod on GameSurge), you can use the !api command to search Nican's API reference:
<theY4Kman> !api Netclass <yakbot> theY4Kman: GetEntityNetClass(edict, String:clsname[], maxlength): Retrieves an entity's networkable serverclass name. This is not the same as the classname and is used for networkable state changes. (http://docs.sourcemod.net/api/index.php?fastload=show&id=66)
How do I find the classname of an entity? (e.g., "weapon_knife" or "prop_physics")
The classname of an entity (not to be confused with a netclass) is a unique identifier. It's the most well known of entity names. To find it, use the function GetEdictClassname():
decl String:classname[128]; GetEdictClassname(myentity, classname, sizeof(classname)); PrintToServer("myentity classname: %s", classname); // myentity classname: weapon_knife
How do I block regular commands, such as kill and say?
As of version 1.3, the recommended way to hook and block commands is with AddCommandListener(). Previously, using RegConsoleCmd() with the command name was the only way to hook commands, but this creates a whole new command for the command dispatch to check every time any command is executed. AddCommandListener() creates only a lightweight hook, processed only when the specific command is executed.
Here's how to use it to block the say command:
public OnPluginStart() { AddCommandListener(SayCallback, "say"); } public Action:SayCallback(client, const String:command[], argc) { Return Plugin_Handled; }
How do I hook +commands, such as +zoom and +attack?
Unlike regular commands, +commands are handled on the client's computer, then sent to the server in a more compressed fashion. This means AddCommandListener() cannot be used to hook +commands. As of version 1.3, the recommended solution is to use the global forward OnPlayerRunCmd(). This forward is fired every time a player uses a movement button. To detect or block a +command, you'll first have to find out its proper IN_ constant (see entity_prop_stocks.inc).
Here's how to use it to block crouching when attacking:
public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon) { // Check if the player is attacking (+attack) if ((buttons & IN_ATTACK) == IN_ATTACK) { // If so, block their crouching (+duck) buttons &= ~IN_DUCK; } // We must return Plugin_Continue to let the changes be processed. // Otherwise, we can return Plugin_Handled to block the commands return Plugin_Continue; }
How do I get rid of loose indentation warnings?
myplugin.sp(#) : warning 217: loose indentation
Loose indentation warnings arise when indentation in your code is inconsistent. This usually means using both tabs and spaces as indentation. However, it can also mean a different amount of spaces or tabs are being used. Therefore, to correct it, use just one type of indentation. Because different editors have different settings for the size of tab stops, it is recommended you use 4 spaces to indent.
Good:
public OnPluginStart() { new myvar = 5; if (myvar == (2 + 3)) PrintToServer("myvar is %d", myvar); }
Bad:
public OnPluginStart() { new myvar = 5; if (myvar == (2 + 3)) PrintToServer("myvar is %d", myvar); }
How do I get rid of tag mismatch warnings?
Though every variable in SourcePawn is one cell (4 bytes), with the exception of strings, there are many different ways to interpret what's inside a cell. To signify a cell's contents, tags are used. The most common are _ (the default tag: a vanilla cell. This tag is implied when no other tag is specified.), Float, bool, and String. See [Introduction to SourcePawn#Variables_2] for more information.
Functions wear these tags on their parameters so you can tell what needs to be passed to the function:
native SetEntPropFloat(entity, PropType:type, const String:prop[], Float:value);
This function calls for entity, a cell with the implied tag _; type, with the developer-defined tag PropType; prop, with the built-in tag String; and value, with the built-in tag Float. To call this function, then, you must pass values with the specified tags. For example:
SetEntPropFloat(1234, Prop_Send, "m_fNumber", 1.0);
This calls the function correctly: 1234 is a regular cell (_), Prop_Send is a variable defined in the enum PropType in entity.inc, "m_fNumber" is a String, and 1.0 is a Float. For a nonexample:
SetEntPropFloat(1234.0, 1, "m_fNumber", 1337);
This is incorrect! 1234.0 is a Float that should be a regular cell (_); 1 is a regular cell (_) that should be a PropType; and 1337 is a regular cell (_) that should be a Float. This call will generate a tag mismatch warning. To correct it, simply use a value with the correct tag. Most of the time, tags that are not built-in (such as PropType) can be found in the same file where a function uses them (you can find PropType in entity.inc).