Developer Console Control
这篇文档解释了怎样编写 控制台 的代码, 也关于怎样创建控制台命令与变量. 看看 开发者控制台 来对控制台的功能有个基本了解.
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. 三个最常见的函数是 Msg()
, DevMsg()
和 Warning()
支持 VarArgs, 例如 sprintf()
:
DevMsg (char const* pMsg, ... ) - only in developer mode Msg(char const* pMsg, ... ) - always, white Warning(char const *pMsg, ... ) - always, red
向下兼容 HL1 的源代码,您仍然可以使用 Con_Printf()
和 Con_DPrintf()
.
执行命令
引擎对服务端与客户端提供了 执行玩家输入的命令 (字符串)的接口. 服务端要使用此接口 IVEngineServer::ServerCommand()
:
engine->ServerCommand("changelevel de_dust\n");
客户端则使用 IVEngineClient
能够在两种函数中选择, 这依赖于是否命令实在客户端执行还是直接被发送到服务端:
engine->ServerCmd( "say hello\n" ); // send command to server
或
engine->ClientCmd( "say hello\n" ); // execute command on client
添加新的命令与变量
开发者控制台是 Source 引擎的子系统,并且通过一个公共接口 ICvar
( 请看 \public\icvar.h
) 它可以被其他的模块所调用. 这些接口允许注册新的命令与查找/迭代(?iterating)已存在的命令. 这些接口通过全局 CVAR 游戏中的 server/client 代码 (cv in engine code). 控制台命令 在 ConCommand
和 ConVar
下的控制台变量 里执行, 这两者都基于类 ConCommandBase
(看看 \public\convar.h
).
太你家命令或变量十分简单,并且在服务端与客户端(甚至是引擎)的模块中,代码是相同的. 这些类的构造会在控制台系统中自动记录下命令. 下面这个简短的例子展示了 添加一个新的命令 my_function 和一个新的初值为 42 的变量 my_variable :
#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 );
一般让对象的名称与命令的名称相同,变量单独在一个源文件中使用并且声明为静态的.
使用 ConVar 类
ConVar s 保存了那些可通过控制台或者 config.cfg 中的内容 来改变的变量. 我们来看看最常用的结构:
ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString )
第一个参数 pName
是一个变量名 (不包含空格), 紧接着的 pDefaultValue
, 通常被用作一个 ConVars 下的数值型的字符串. Flags
确定变量 &mdash 中的特殊字符; 所有的 flag 以 FCVAR_
作为前缀被定义. 更多的关于 flags 的东东可以在这里找到 below. 最好也提供一个 pHelpString
, 这样玩家对这个变量的作用能有所了解. ConVars 并没有被限定为固定类型, 他们的值可以是 整型(integer) 、 浮点型(float) 或 字符串(string) ,你喜欢什么就用什么. 只要您让 ConVar (?object itself) 或作为一个指针, 您可以直接存取或修改它的值. 下面这些例子都是有效的并且有相同的结果:
if ( my_variable.GetInt() == 42 ) DoSomething(); if ( my_variable.GetFloat() == 42.0f ) DoSomething(); if ( strcmp(my_variable.GetString(), "42")==0 ) DoSomething();
设置 ConVar 的值,您可以使用 SetValue()
函数, 它同样允许各种类型的值:
my_variable.SetValue( 42 ); my_variable.SetValue( 42.0f ); my_variable.SetValue( "42" );
任何时候您都可以使用 Revert()
函数 使 ConVar 回到他的初始默认值.
如果 ConVar 在不同的模块中被创建,在变量名为已知的情况下 ICvar
接口函数 FindVar()
可以被用来指向这个对象. 这是一个代价很大的搜索功能,如果经常重复使用,指针将被缓存. 这里是一个例子展示了怎样查找在引擎模块中定义的 ConVar sv_cheats :
ConVar *pCheats = cvar->FindVar( "sv_cheats" ); if ( pCheats && pCheats->GetInt() == 1 ) AllowCheating();
不同情况下,对于 ConVars 的有效的数值范围需要被指定. 无论何时手动改变了, ConVar 都会自动被控制台系统所检查. 如果输入的数值超出了范围, 它将被替换为最相近的值. 设置有效范围为 1 到 100 :
ConVar my_variable( "my_variable", "42", 0, "helptext", true, 1, true, 100 );
当玩家或者另一个子系统改变了您的 ConVar 值时,您可能会需要一个通知, 因此,一个回显函数就需要被安置:
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.