Developer Console Control: Difference between revisions
TomEdwards (talk | contribs) m (→Using ConVar) |
m (tidy & excess linkage & typos & grammar) |
||
Line 1: | Line 1: | ||
This document explains how to write code that prints to the [[console]], as well as how to execute and create console commands and variables. See [[Developer Console]] for an overview of console features. | This document explains how to write code that prints to the [[console]], as well as how to execute and create console commands and variables. See [[Developer Console]] for an overview of console features. | ||
==Printing to the console== | == Printing to the console == | ||
Printing text to the console is done the same way in all modules, since the Tier0 debug layer provides these routines. The | Printing text to the console is done the same way in all modules, since the [[Tier0]] debug layer provides these routines. The three most common functions are <code>Msg()</code>, <code>DevMsg()</code> and <code>Warning()</code> which all support VarArgs, like <code>sprintf()</code>: | ||
DevMsg (char const* pMsg, ... ) - only in developer mode | DevMsg (char const* pMsg, ... ) - only in developer mode | ||
Line 11: | Line 11: | ||
For backward compatibility with HL1 source code you can still use <code>Con_Printf()</code> and <code>Con_DPrintf()</code>. | For backward compatibility with HL1 source code you can still use <code>Con_Printf()</code> and <code>Con_DPrintf()</code>. | ||
==Executing commands== | == Executing commands == | ||
The engine provides interface to server and client code to execute commands (strings) from code as if the user would have entered them. The server has to use the interface <code>IVEngineServer::ServerCommand()</code>: | The engine provides interface to server and client code to execute commands (strings) from code as if the user would have entered them. The server has to use the interface <code>IVEngineServer::ServerCommand()</code>: | ||
Line 25: | Line 25: | ||
engine->ClientCmd( "say hello\n" ); // execute command on client | engine->ClientCmd( "say hello\n" ); // execute command on client | ||
==Adding | == Adding new commands & variables== | ||
The developer console is a subsystem provided by the Source engine and is accessible for all other modules via a public interface <code>ICvar</code> ( see <code>\public\icvar.h</code>). This interface allows registering new commands and finding/iterating existing commands. This interface is available via the global [[CVAR]] | The developer console is a subsystem provided by the Source engine and is accessible for all other modules via a public interface <code>ICvar</code> ( see <code>\public\icvar.h</code>). This interface allows registering new commands and finding/iterating existing commands. This interface is available via the global [[CVAR]] in-game server/client code (cv in engine code). [[Console command]]s are implemented in <code>ConCommand</code> and [[Console Variable|console_variables]] in <code>ConVar</code>, which both derive from the base class <code>ConCommandBase</code> (see <code>\public\convar.h</code>). | ||
Adding a new command or variable is fairly simple and the same code in both server and client (even engine) modules. The constructor of these classes automatically registers the command at the console system. This short example code adds a new command my_function and a new variable my_variable initialized to 42: | Adding a new command or variable is fairly simple and the same code in both server and client (even engine) modules. The constructor of these classes automatically registers the command at the console system. This short example code adds a new command my_function and a new variable my_variable initialized to 42: | ||
Line 43: | Line 43: | ||
It is common use that the object name and the command name are the same and variables used only in a single source file are declared as static. | It is common use that the object name and the command name are the same and variables used only in a single source file are declared as static. | ||
==Using ConVar== | == Using the ConVar class == | ||
[[ConVar]]s store variables that can be altered through the console and (optionally) saved in config.cfg. Let's take a look at the most used constructor: | [[ConVar]]s store variables that can be altered through the console and (optionally) saved in config.cfg. Let's take a look at the most used constructor: | ||
Line 52: | Line 52: | ||
char const *pHelpString ) | char const *pHelpString ) | ||
The first argument <code>pName</code> is the variable name (no spaces), followed by <code>pDefaultValue</code>, which is always given as a string even for | The first argument <code>pName</code> is the variable name (no spaces), followed by <code>pDefaultValue</code>, which is always given as a string even for ConVars with numerical values. <code>Flags</code> specify special characteristics of the variable — all flag definitions start with a <code>FCVAR_</code> prefix. More information about these flags can be found [[#The FCVAR flags|below]]. It's always good to provide a <code>pHelpString</code>, so users get an idea what this variable is about. ConVars are not bound to a certain type, their value can be an integer or a float or string and you may use it however you like. As long as you have the ConVar object itself or as a pointer, you can access and modify its values directly. All these examples are valid and have the same result: | ||
if ( my_variable.GetInt() == 42 ) DoSomething(); | if ( my_variable.GetInt() == 42 ) DoSomething(); | ||
Line 58: | Line 58: | ||
if ( strcmp(my_variable.GetString(), "42")==0 ) DoSomething(); | if ( strcmp(my_variable.GetString(), "42")==0 ) DoSomething(); | ||
To set the value of a | To set the value of a ConVar you should use the <code>SetValue()</code> function, which also allows all types of data: | ||
my_variable.SetValue( 42 ); | my_variable.SetValue( 42 ); | ||
Line 64: | Line 64: | ||
my_variable.SetValue( "42" ); | my_variable.SetValue( "42" ); | ||
At any time you can revert a | At any time you can revert a ConVar back to it's original default value by using the <code>Revert()</code> function. | ||
If a | If a ConVar is created in a different module, the <code>ICvar</code> interface function <code>FindVar()</code> can be used to get a pointer to this object, if the variable name is known. This is an expensive search function and the pointer should be cached if reused often. Here is an example how to check the ConVar [[sv_cheats]] defined in the engine module: | ||
ConVar *pCheats = cvar->FindVar( "sv_cheats" ); | ConVar *pCheats = cvar->FindVar( "sv_cheats" ); | ||
Line 72: | Line 72: | ||
if ( pCheats && pCheats->GetInt() == 1 ) AllowCheating(); | if ( pCheats && pCheats->GetInt() == 1 ) AllowCheating(); | ||
A range of valid values can be specified for numerical | A range of valid values can be specified for numerical ConVars using a different constructor. Then a ConVar is automatically checked by the console system whenever changed manually. If the entered number is out of range, it's rounded to the next valid value. Setting valid range from 1 to 100: | ||
ConVar my_variable( "my_variable", "42", 0, "helptext", true, 1, true, 100 ); | ConVar my_variable( "my_variable", "42", 0, "helptext", true, 1, true, 100 ); | ||
Sometimes you also want a notification when a user's or another subsystem changes your | Sometimes you also want a notification when a user's or another subsystem changes your ConVar value, therefore a callback function can be installed: | ||
static void OnChangeMyVariable ( ConVar *var, char const *pOldString ) | static void OnChangeMyVariable ( ConVar *var, char const *pOldString ) | ||
Line 85: | Line 85: | ||
ConVar my_variable( "my_variable", "42", 0, "My favorite number", OnChangeMyVariable ); | ConVar my_variable( "my_variable", "42", 0, "My favorite number", OnChangeMyVariable ); | ||
==Using the class | == Using the ConCommand class == | ||
The <code>class</code> ConCommand does not store a value, but instead executes a procedure as soon as it is invoked. It is simpler than the ConVar and has just one constructor: | The <code>class</code> ConCommand does not store a value, but instead executes a procedure as soon as it is invoked. It is simpler than the ConVar and has just one constructor: | ||
Line 95: | Line 95: | ||
FnCommandCompletionCallback completionFunc = 0 ); | FnCommandCompletionCallback completionFunc = 0 ); | ||
As in ConVar <code>pName</code> specifies the command name (no spaces | As in ConVar, <code>pName</code> specifies the command name (no spaces). <code>callback</code> is the function executed when a user runs this command and both <code>pHelpString</code> and <code>flags</code> have the same function as in ConVar. ConCommands supports auto completion for the first parameter, which is useful especially for commands that process files. For example, if you have a command <code>loadtext lt;textfilegt</code>; that expects a .txt file as input, the console scans for all available .txt files and allows the user to choose one from a list. If a valid <code>completionFunc</code> is passed, it will be called whenever the console system needs a list of available arguments. | ||
When the <code>callback</code> function is executed, the parameters entered in console are not passed as function arguments. The <code>callback</code> function has to query the engine how many arguments where given using the engine interface function <code>Cmd_Argc()</code>. Then you can look at single arguments using <code>Cmd_Argv(index)</code>, where index 1 is the first argument. The arguments are always returned as strings. | When the <code>callback</code> function is executed, the parameters entered in the console are not passed as function arguments. The <code>callback</code> function has to query the engine how many arguments where given using the engine interface function <code>Cmd_Argc()</code>. Then you can look at single arguments using <code>Cmd_Argv(index)</code>, where index 1 is the first argument. The arguments are always returned as strings. | ||
void MySay_f ( void ) | void MySay_f ( void ) | ||
Line 124: | Line 124: | ||
ConCommand my_say( "my_say", MySay_f, "say something", 0, MySayAutoComplete); | ConCommand my_say( "my_say", MySay_f, "say something", 0, MySayAutoComplete); | ||
==The FCVAR flags== | == The FCVAR flags == | ||
The console command/variable flags can specify quite powerful characteristics and must be handled with care. These flags are usually set in the constructor but may be modified with <code>ConCommandBase::AddFlags()</code> (not used very often). It's not possible to change these flags other than in source code to avoid cheating. | The console command/variable flags can specify quite powerful characteristics and must be handled with care. These flags are usually set in the constructor but may be modified with <code>ConCommandBase::AddFlags()</code> (not used very often). It's not possible to change these flags other than in source code to avoid cheating. | ||
Some flags must be set manually, but those in the list below are set automatically by | Some flags must be set manually, but those in the list below are set automatically by the console system: | ||
*FCVAR_LAUNCHER | *FCVAR_LAUNCHER | ||
Line 142: | Line 142: | ||
:The game server's setting of <code>sv_cheats</code> decides if cheats are enabled or not. If a client connects to a server where cheats are disabled (should be the default case), all client side console variables labeled as <code>FCVAR_CHEAT</code> are reverted to their default values and can't be changed as long as the client stays connected. Console commands marked as <code>FCVAR_CHEAT</code> can't be executed either. | :The game server's setting of <code>sv_cheats</code> decides if cheats are enabled or not. If a client connects to a server where cheats are disabled (should be the default case), all client side console variables labeled as <code>FCVAR_CHEAT</code> are reverted to their default values and can't be changed as long as the client stays connected. Console commands marked as <code>FCVAR_CHEAT</code> can't be executed either. | ||
;<code>FCVAR_USERINFO</code> | ;<code>FCVAR_USERINFO</code> | ||
:Some console variables contain client information the server needs to know about, like the player's name or his network settings. These variables must be flagged as <code>FCVAR_USERINFO</code>, so they get transmitted to the server and updated every time the user changes them. When the player changes | :Some console variables contain client information the server needs to know about, like the player's name or his network settings. These variables must be flagged as <code>FCVAR_USERINFO</code>, so they get transmitted to the server and updated every time the user changes them. When the player changes one of these variables the engine notifies the server code via <code>ClientSettingsChanged()</code>. Then the game server can query the engine for specific client settings with <code>GetClientConVarValue()</code>. | ||
;<code>FCVAR_REPLICATED</code> | ;<code>FCVAR_REPLICATED</code> | ||
:Game server and client are using shared code where it's important that both sides run the exact | :Game server and client are using shared code where it's important that both sides run the exact same path using the same data (e.g. predicted movement/weapons, game rules). If this code uses console variables, they must match the same values on both sides. The flag <code>FCVAR_REPLICATED</code> ensures that by broadcasting these values to all clients. While connected, clients can't change these values and are forced to use the server-side values. | ||
;<code>FCVAR_ARCHIVE</code> | ;<code>FCVAR_ARCHIVE</code> | ||
:Some console variables contain user specific settings we want to restore each time the game is started ( like name or <code>network_rate</code>). If a console variable is labeled as <code>FCVAR_ARCHIVE</code>, it is saved in the file <code>config.cfg</code> when the game shuts down and is reloaded with the next start. (Also the command <code>host_writeconfig</code> stores all <code>FCVAR_ARCHIVE</code> variables to a file). | :Some console variables contain user specific settings we want to restore each time the game is started (like <code>name</code> or <code>network_rate</code>). If a console variable is labeled as <code>FCVAR_ARCHIVE</code>, it is saved in the file <code>config.cfg</code> when the game shuts down and is reloaded with the next start. (Also the command <code>host_writeconfig</code> stores all <code>FCVAR_ARCHIVE</code> variables to a file). | ||
;<code>FCVAR_NOTIFY</code> | ;<code>FCVAR_NOTIFY</code> | ||
:If a console variable is flagged as <code>FCVAR_NOTIFY</code>, a server sends a notification message to all clients whenever this variable is changed. This should be used for variables that change game play rules, which are important for all players (<code>mp_friendlyfire</code> etc). | :If a console variable is flagged as <code>FCVAR_NOTIFY</code>, a server sends a notification message to all clients whenever this variable is changed. This should be used for variables that change game play rules, which are important for all players (<code>mp_friendlyfire</code> etc). | ||
Line 152: | Line 152: | ||
:If console variables contain private information (passwords etc), we don't want them to be visible to other players. Then the <code>FCVAR_PROTECTED</code> flag should be set to label this information as confidential. | :If console variables contain private information (passwords etc), we don't want them to be visible to other players. Then the <code>FCVAR_PROTECTED</code> flag should be set to label this information as confidential. | ||
;<code>FCVAR_SPONLY</code> | ;<code>FCVAR_SPONLY</code> | ||
:Sometimes executing commands or changing variables may be valid only in single player mode | :Sometimes executing commands or changing variables may be valid only in single player mode. If this is the case then label these commands as <code>FCVAR_SPONLY</code>. | ||
;<code>FCVAR_PRINTABLEONLY</code> | ;<code>FCVAR_PRINTABLEONLY</code> | ||
:Some important variables are logged or broadcasted (gamerules etc) and it is important that they contain only printable characters (no control chars etc). | :Some important variables are logged or broadcasted (gamerules etc) and it is important that they contain only printable characters (no control chars etc). | ||
;<code>FCVAR_NEVER_AS_STRING</code> | ;<code>FCVAR_NEVER_AS_STRING</code> | ||
:The flag tells the engine never to print this variable as string since it contains control sequences. | :The <code>FCVAR_NEVER_AS_STRING</code> flag tells the engine never to print this variable as a string since it contains control sequences. | ||
;<code>FCVAR_DEMO</code> | ;<code>FCVAR_DEMO</code> | ||
:When starting | :When starting to record a demo file, some console variables must explicitly be added to the recording to ensure a correct playback. | ||
;<code>FCVAR_DONTRECORD</code> | ;<code>FCVAR_DONTRECORD</code> | ||
:This is the opposite of FCVAR_DEMO, some console commands shouldn't be recorded in demo files. | :This is the opposite of FCVAR_DEMO, some console commands shouldn't be recorded in demo files. |
Revision as of 17:41, 2 February 2008
This document explains how to write code that prints to the console, as well as how to execute and create console commands and variables. See Developer Console for an overview of console features.
Printing to the console
Printing text to the console is done the same way in all modules, since the Tier0 debug layer provides these routines. The three most common functions are Msg()
, DevMsg()
and Warning()
which all support VarArgs, like sprintf()
:
DevMsg (char const* pMsg, ... ) - only in developer mode Msg(char const* pMsg, ... ) - always, white Warning(char const *pMsg, ... ) - always, red
For backward compatibility with HL1 source code you can still use Con_Printf()
and Con_DPrintf()
.
Executing commands
The engine provides interface to server and client code to execute commands (strings) from code as if the user would have entered them. The server has to use the interface IVEngineServer::ServerCommand()
:
engine->ServerCommand("changelevel de_dust\n");
Client code has to use the interface IVEngineClient
and can choose here between two functions, depending if the command should be executed on the client first or be sent directly to the server:
engine->ServerCmd( "say hello\n" ); // send command to server
or
engine->ClientCmd( "say hello\n" ); // execute command on client
Adding new commands & variables
The developer console is a subsystem provided by the Source engine and is accessible for all other modules via a public interface ICvar
( see \public\icvar.h
). This interface allows registering new commands and finding/iterating existing commands. This interface is available via the global CVAR in-game server/client code (cv in engine code). Console commands are implemented in ConCommand
and console_variables in ConVar
, which both derive from the base class ConCommandBase
(see \public\convar.h
).
Adding a new command or variable is fairly simple and the same code in both server and client (even engine) modules. The constructor of these classes automatically registers the command at the console system. This short example code adds a new command my_function and a new variable my_variable initialized to 42:
#include <convar.h> ConVar my_variable( "my_variable", "42", FCVAR_ARCHIVE, "My favorite number" ); void MyFunction_f( void ) { Msg("This is my function\n"); } ConCommand my_function( "my_function", MyFunction_f, "Shows a message.", FCVAR_CHEAT );
It is common use that the object name and the command name are the same and variables used only in a single source file are declared as static.
Using the ConVar class
ConVars store variables that can be altered through the console and (optionally) saved in config.cfg. Let's take a look at the most used constructor:
ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString )
The first argument pName
is the variable name (no spaces), followed by pDefaultValue
, which is always given as a string even for ConVars with numerical values. Flags
specify special characteristics of the variable — all flag definitions start with a FCVAR_
prefix. More information about these flags can be found below. It's always good to provide a pHelpString
, so users get an idea what this variable is about. ConVars are not bound to a certain type, their value can be an integer or a float or string and you may use it however you like. As long as you have the ConVar object itself or as a pointer, you can access and modify its values directly. All these examples are valid and have the same result:
if ( my_variable.GetInt() == 42 ) DoSomething(); if ( my_variable.GetFloat() == 42.0f ) DoSomething(); if ( strcmp(my_variable.GetString(), "42")==0 ) DoSomething();
To set the value of a ConVar you should use the SetValue()
function, which also allows all types of data:
my_variable.SetValue( 42 ); my_variable.SetValue( 42.0f ); my_variable.SetValue( "42" );
At any time you can revert a ConVar back to it's original default value by using the Revert()
function.
If a ConVar is created in a different module, the ICvar
interface function FindVar()
can be used to get a pointer to this object, if the variable name is known. This is an expensive search function and the pointer should be cached if reused often. Here is an example how to check the ConVar sv_cheats defined in the engine module:
ConVar *pCheats = cvar->FindVar( "sv_cheats" ); if ( pCheats && pCheats->GetInt() == 1 ) AllowCheating();
A range of valid values can be specified for numerical ConVars using a different constructor. Then a ConVar is automatically checked by the console system whenever changed manually. If the entered number is out of range, it's rounded to the next valid value. Setting valid range from 1 to 100:
ConVar my_variable( "my_variable", "42", 0, "helptext", true, 1, true, 100 );
Sometimes you also want a notification when a user's or another subsystem changes your ConVar value, therefore a callback function can be installed:
static void OnChangeMyVariable ( ConVar *var, char const *pOldString ) { DevMsg( "ConVar %s was changed from %s to %s\n", var->GetName(), pOldString, var->GetString() ); } ConVar my_variable( "my_variable", "42", 0, "My favorite number", OnChangeMyVariable );
Using the ConCommand class
The class
ConCommand does not store a value, but instead executes a procedure as soon as it is invoked. It is simpler than the ConVar and has just one constructor:
ConCommand( char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
As in ConVar, pName
specifies the command name (no spaces). callback
is the function executed when a user runs this command and both pHelpString
and flags
have the same function as in ConVar. ConCommands supports auto completion for the first parameter, which is useful especially for commands that process files. For example, if you have a command loadtext lt;textfilegt
; that expects a .txt file as input, the console scans for all available .txt files and allows the user to choose one from a list. If a valid completionFunc
is passed, it will be called whenever the console system needs a list of available arguments.
When the callback
function is executed, the parameters entered in the console are not passed as function arguments. The callback
function has to query the engine how many arguments where given using the engine interface function Cmd_Argc()
. Then you can look at single arguments using Cmd_Argv(index)
, where index 1 is the first argument. The arguments are always returned as strings.
void MySay_f ( void ) { if ( engine->Cmd_Argc() < 1 ) { Msg(""Usage: my_say <text>\n"); return; } Msg("I say: %s\n", engine->Cmd_Argv(1) ); } ConCommand my_say( "my_say", MySay_f, "say something", 0);
Here an example how to build a simple auto complete list. The partial parameter isn't used here; it contains the characters entered so far (including the command name itself) :
static int MySayAutoComplete ( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) { strcpy( commands[0], "hello" ); strcpy( commands[1], "goodbye" ); return 2; // number of entries } ConCommand my_say( "my_say", MySay_f, "say something", 0, MySayAutoComplete);
The FCVAR flags
The console command/variable flags can specify quite powerful characteristics and must be handled with care. These flags are usually set in the constructor but may be modified with ConCommandBase::AddFlags()
(not used very often). It's not possible to change these flags other than in source code to avoid cheating.
Some flags must be set manually, but those in the list below are set automatically by the console system:
- FCVAR_LAUNCHER
- FCVAR_GAMEDLL
- FCVAR_CLIENTDLL
- FCVAR_MATERIAL_SYSTEM
- FCVAR_STUDIORENDER
The remaining flags must be set manually:
FCVAR_CHEAT
- Most commands and variables are for debugging proposes and not removed in release builds since they are useful 3rd party developers and map makers too. Unfortunately we cannot allow normal players to use these debugging tools since it's an unfair advantage over other players (cheating). A good rule is to add
FCVAR_CHEAT
basically to every new console command you add unless it's an explicit and legitimate options setting for players. Experience shows that even the most harmless looking debugging command can be misused as a cheat somehow. - The game server's setting of
sv_cheats
decides if cheats are enabled or not. If a client connects to a server where cheats are disabled (should be the default case), all client side console variables labeled asFCVAR_CHEAT
are reverted to their default values and can't be changed as long as the client stays connected. Console commands marked asFCVAR_CHEAT
can't be executed either. FCVAR_USERINFO
- Some console variables contain client information the server needs to know about, like the player's name or his network settings. These variables must be flagged as
FCVAR_USERINFO
, so they get transmitted to the server and updated every time the user changes them. When the player changes one of these variables the engine notifies the server code viaClientSettingsChanged()
. Then the game server can query the engine for specific client settings withGetClientConVarValue()
. FCVAR_REPLICATED
- Game server and client are using shared code where it's important that both sides run the exact same path using the same data (e.g. predicted movement/weapons, game rules). If this code uses console variables, they must match the same values on both sides. The flag
FCVAR_REPLICATED
ensures that by broadcasting these values to all clients. While connected, clients can't change these values and are forced to use the server-side values. FCVAR_ARCHIVE
- Some console variables contain user specific settings we want to restore each time the game is started (like
name
ornetwork_rate
). If a console variable is labeled asFCVAR_ARCHIVE
, it is saved in the fileconfig.cfg
when the game shuts down and is reloaded with the next start. (Also the commandhost_writeconfig
stores allFCVAR_ARCHIVE
variables to a file). FCVAR_NOTIFY
- If a console variable is flagged as
FCVAR_NOTIFY
, a server sends a notification message to all clients whenever this variable is changed. This should be used for variables that change game play rules, which are important for all players (mp_friendlyfire
etc). FCVAR_PROTECTED
- If console variables contain private information (passwords etc), we don't want them to be visible to other players. Then the
FCVAR_PROTECTED
flag should be set to label this information as confidential. FCVAR_SPONLY
- Sometimes executing commands or changing variables may be valid only in single player mode. If this is the case then label these commands as
FCVAR_SPONLY
. FCVAR_PRINTABLEONLY
- Some important variables are logged or broadcasted (gamerules etc) and it is important that they contain only printable characters (no control chars etc).
FCVAR_NEVER_AS_STRING
- The
FCVAR_NEVER_AS_STRING
flag tells the engine never to print this variable as a string since it contains control sequences. FCVAR_DEMO
- When starting to record a demo file, some console variables must explicitly be added to the recording to ensure a correct playback.
FCVAR_DONTRECORD
- This is the opposite of FCVAR_DEMO, some console commands shouldn't be recorded in demo files.