Difference between revisions of "SourcePawn Basics - Customization through ConVars"
m (→Catching that a ConVar changed) |
NgBUCKWANGS (talk | contribs) |
||
(2 intermediate revisions by one other user not shown) | |||
Line 99: | Line 99: | ||
Here is how you read a bool ConVar: | Here is how you read a bool ConVar: | ||
− | new bool:value = | + | new bool:value = GetConVarBool(g_hAutoTeamBalance); |
and to set the same ConVar: | and to set the same ConVar: | ||
− | + | SetConVarBool(g_hAutoTeamBalance, true); | |
Int and Floats work roughly the same way with <tt>GetConVarInt</tt> / <tt>GetConVarFloat</tt> / <tt>SetConVarInt</tt> / <tt>SetConVarFloat</tt>. | Int and Floats work roughly the same way with <tt>GetConVarInt</tt> / <tt>GetConVarFloat</tt> / <tt>SetConVarInt</tt> / <tt>SetConVarFloat</tt>. | ||
Line 118: | Line 118: | ||
In addition to just reading and changing ConVar values, you can also catch when a ConVar's value is changed. | In addition to just reading and changing ConVar values, you can also catch when a ConVar's value is changed. | ||
− | This is done through a ConVarChange hook. | + | This is done through a ConVarChange hook. ConVarChange hooks only fire when the value changes from one state to another. So, if a ConVar is already set to 1 and a config changes it to 1 (the same value), the ConVarChange hook will '''not''' fire. |
You can add a ConVarChange hook like this: | You can add a ConVarChange hook like this: | ||
Line 149: | Line 149: | ||
'''Make sure you hook the ConVar in the same function you Create or Find it.''' It's also a good idea to check the return value of FindConVar before hooking it, as a game that doesn't support a ConVar will return <tt>INVALID_HANDLE</tt> | '''Make sure you hook the ConVar in the same function you Create or Find it.''' It's also a good idea to check the return value of FindConVar before hooking it, as a game that doesn't support a ConVar will return <tt>INVALID_HANDLE</tt> | ||
+ | |||
+ | == Reading ConVars from server.cfg ASAP == | ||
+ | On server first launch, ConVars in server.cfg are loaded later than OnPluginStart (e.g, see <strong>Q: Can I get cvar values in OnPluginStart?</strong> on this page http://www.sourcemod.net/devlog/?p=126). A working example of how to read from server.cfg ASAP but falling back to a default value in case it doesn't exist follows. | ||
+ | |||
+ | ConVar g_YourConVar; | ||
+ | new g_YourGlobalVar; | ||
+ | |||
+ | public OnPluginStart() { | ||
+ | g_YourConVar = CreateConVar("your_convar", "your_default_value"); | ||
+ | g_YourGlobalVar = g_YourConVar.IntValue; | ||
+ | HookConVarChange(g_YourConVar, YourGlobalVarHook); | ||
+ | } | ||
+ | |||
+ | public YourGlobalVarHook(Handle:convar, const String:oldValue[], const String:newValue[]) { | ||
+ | g_YourGlobalVar = GetConVarInt(g_YourConVar); | ||
+ | PrintToServer("g_YourGlobalVar Has Changed: %d", g_YourGlobalVar); | ||
+ | } | ||
[[Category:SourcePawn Basics]] | [[Category:SourcePawn Basics]] |
Latest revision as of 06:25, 5 November 2016
Prerequisite: This guide assumes you have read Introduction to SourcePawn and Introduction to SourceMod Plugins.
Server owners like customization. Lots of customization. So, how do you add customization to your plugin? The simplest route is by adding ConVars.
Contents
General Info
Console Variables (ConVars or CVars for short) are server settings that can be changed by server owners. Anything you put into your server's server.cfg file is a convar.
Just like the server itself, plugins can create their own convars. A convar is different from a regular variable in that it is visible outside your plugin.
Creating your own ConVars
ConVars should always be created in OnPluginStart.
When you create your ConVars, they should name them consistently. A good naming practice is nameofplugin_settingname or nameofplugin_setting_name.
ConVars are created via the CreateConVar command. The order of arguments are:
- name
- The convar name, preferably using the naming scheme above
- defaultValue
- A string with the default value.
- description
- A description of what this ConVar does for the find or listcvars commands
- flags
- An | separate list of convar flags
- hasMin
- A bool stating whether the min argument exists
- min
- A Float with the minimum allowed value
- hasMax
- A bool stating whether the max argument exists
- min
- A Float with the maximum allowed value
Useful ConVar Flags
- FCVAR_NONE - The default, no flags set.
- FCVAR_PROTECTED - Used for passwords. Don't send this value to clients who ask for it, only send 1 if it's set or 0 if it isn't.
- FCVAR_SPONLY - Not changeable in multiplayer
- FCVAR_NOTIFY - Players are informed when this ConVar changes. ConVars marked with this attribute are also visible to tracking services.
- FCVAR_NEVER_AS_STRING - Don't try to print this out
- FCVAR_DONTRECORD - Not recorded in demo files. Also, not recorded in AutoExecConfig files.
- FCVAR_PLUGIN - Defined by a 3rd Party plugin. SourceMod probably adds this already even if you don't.
Standard ConVars
There are a few standard ConVars that most plugins have.
The first is a version ConVar. Unlike most ConVars, you don't need to store the Handle of this one as you never need to read its value.
Normally, your version ConVar will look a little like this.
#define VERSION "1.0" public OnPluginStart() { CreateConVar("test_version", VERSION, "Test Plugin version", FCVAR_NOTIFY|FCVAR_DONTRECORD|FCVAR_PLUGIN|FCVAR_SPONLY); }
|FCVAR_PLUGIN|FCVAR_SPONLY is not strictly required here, but it is fairly common to see them set.
VERSION is defined here so that it can be used in the plugin's myinfo struct as well.
A second common ConVar is the enable ConVar.
new Handle:g_hEnabled; public OnPluginStart() { g_hEnabled = CreateConVar("test_enable", "1", "Test Plugin Enable", FCVAR_NOTIFY|FCVAR_DONTRECORD, true, 0.0, true, 1.0); }
Note that FCVAR_DONTRECORD is still present. This is a recommendation in case your plugin has an AutoExecConfig file so that your enable ConVar can be controlled by map configurations or server.cfg.
FCVAR_NOTIFY is here as well so that GameTracker and the like can tell if the plugin is enabled.
Loading ConVars from a file
SourceMod has a command AutoExecConfig to automatically read/create a ConVar configuration file. To use it, put this at the end of OnPluginStart after your CreateConVar lines:
AutoExecConfig(true, "nameofplugin");
which will create a file named cfg/sourcemod/nameofplugin.cfg
Locating ConVars from the game or other plugins
Looking up plugins is an expensive operation and should be done just once if you can help it.
The best location to do this is in the OnAllPluginsLoaded callback.
For example, here is how to look up the mp_autoteambalance ConVar
new Handle:g_hAutoTeamBalance; public OnAllPluginsLoaded() { g_hAutoTeamBalance = FindConVar("mp_autoteambalance"); }
Reading and Setting ConVars
Both ConVars from your plugin and ConVars from the game or other plugins can be read the same way.
ConVars can be read as several different kinds of values: cell (int), bool, Float, or String.
Here is how you read a bool ConVar:
new bool:value = GetConVarBool(g_hAutoTeamBalance);
and to set the same ConVar:
SetConVarBool(g_hAutoTeamBalance, true);
Int and Floats work roughly the same way with GetConVarInt / GetConVarFloat / SetConVarInt / SetConVarFloat.
Strings work the same for setting, but reading a String ConVar works slightly differently:
decl String:value[64]; GetConVarString(myConVar, value, sizeof(value));
This pattern is common for functions that do String manipulations.
Catching that a ConVar changed
In addition to just reading and changing ConVar values, you can also catch when a ConVar's value is changed.
This is done through a ConVarChange hook. ConVarChange hooks only fire when the value changes from one state to another. So, if a ConVar is already set to 1 and a config changes it to 1 (the same value), the ConVarChange hook will not fire.
You can add a ConVarChange hook like this:
new Handle:g_hEnabled; public OnPluginStart() { g_hEnabled = CreateConVar("test_enable", "1", "Test Plugin Enable", FCVAR_NOTIFY|FCVAR_DONTRECORD, true, 0.0, true, 1.0); HookConVarChange(g_hEnabled, ConVar_EnableChange); } public ConVar_EnableChange(Handle:convar, const String:oldValue[], const String:newValue[]) { new enabled = GetConVarBool(g_hEnabled); if (enabled) { // We were just enabled } else { // We were just disabled } }
Note that it's quicker to use GetConVarBool, Int, or Float instead of converting oldValue or newValue to the appropriate types.
There is also an UnhookConVarChange, but it is largely unnecessary as these hooks are automatically released when your plugin unloads.
Make sure you hook the ConVar in the same function you Create or Find it. It's also a good idea to check the return value of FindConVar before hooking it, as a game that doesn't support a ConVar will return INVALID_HANDLE
Reading ConVars from server.cfg ASAP
On server first launch, ConVars in server.cfg are loaded later than OnPluginStart (e.g, see Q: Can I get cvar values in OnPluginStart? on this page http://www.sourcemod.net/devlog/?p=126). A working example of how to read from server.cfg ASAP but falling back to a default value in case it doesn't exist follows.
ConVar g_YourConVar; new g_YourGlobalVar; public OnPluginStart() { g_YourConVar = CreateConVar("your_convar", "your_default_value"); g_YourGlobalVar = g_YourConVar.IntValue; HookConVarChange(g_YourConVar, YourGlobalVarHook); } public YourGlobalVarHook(Handle:convar, const String:oldValue[], const String:newValue[]) { g_YourGlobalVar = GetConVarInt(g_YourConVar); PrintToServer("g_YourGlobalVar Has Changed: %d", g_YourGlobalVar); }