Управление терминалом разработчика
Этот документ объясняет, как писать код, выводящий текст в терминал, а также, как исполнять и создавать команды и переменные управления. Смотрите Терминал разработчика для обзора возможностей терминала.
Печать в терминал
Ввод текста в терминал доступен из всех модулей и контролируется через Tier(). Есть 3 дополнительные команды Msg(), DevMsg() и Warning() которые поддерживают вывод форматированной строки, как sprintf():
DevMsg (char const* pMsg, ... ) - только в режиме разработчика
Msg(char const* pMsg, ... ) - всегда, белый текст
Warning(char const *pMsg, ... ) - всегда, красный текст
Для обратной совместимости с HL1 сохранены команды Con_Printf() и Con_DPrintf().
Подстановка переменных:
Вещественных (Float):
DevMsg("Подстановка значения этой переменной: %.2f", floatVariable)
Целых (Integer):
DevMsg("Подстановка значения этой переменной: %i", integerVariable)
Строк (String):
DevMsg("Подстановка значения этой переменной: %s", stringVariable)
Нескольких переменных:
DevMsg("Подстановка значения этой %i, а так же %s и %.2f переменных", integerVariable, stringVariable, floatVariable)
Include \n to create carriage return, ready to output on line below when Msg/DevMsg next called.
Установка значений переменных
[the_cvar]->SetValue( [value] );
Если нет доступа к переменной cvar, сначала сделайте следующее:
ConVar *[the_cvar] = cvar->FindVar( "[the_cvar]" );
Это работает даже для переменных cvar с закрытым исходным кодом.
Исполнение команд
Движок использует интерфейс сервера и клиента, чтобы исполнять команды (строки). Сервер использует интерфейс IVEngineServer::ServerCommand():
engine->ServerCommand("changelevel de_dust\n");
Клиент использует интерфейс IVEngineClient и выбирает между двумя командами, от этого зависит, будет ли команда исполняться сначала на клиенте или посылаться непосредственно серверу:
engine->ServerCmd( "say hello\n" ); // послать команду на сервер
или
engine->ClientCmd( "say hello\n" ); // выполнить команду на клиенте
Если нужно выполнить команду управления на клиенте с сервера, используйте:
engine->ClientCommand( edict(), "command", ... );
Where edict() is your ent's edict, "command" would be replaced by your concommand, followed by any formatted vars (same as printf). This would be useful for showing a team selection menu.
Добавление новых команд и переменных
Терминал разработчика - это подсистема движка Source, которая дает доступ к различным модулям, это осуществляется через интерфейс ICvar ( см. \public\icvar.h). Этот интерфейс регистрирует новые команды и ищет существующие. Этот интрефейс доступен через глобальную переменную ConVar в клиент-серверном коде (cv в коде движка). Команды управления принадлежат классу ConCommand, а переменные управления классу ConVar, оба они происходят от основного класса ConCommandBase (см. \public\convar.h).
Добавление новых команд и переменных довольно просто и дуступно для использования и для серверных и для клиентских (одинаково для всего движка) модулей. Конструктор этих классов автоматически регистрирует новую команду/переменную в системе терминала. Этот короткий пример кода добавляет новую команду my_function и новую переменную my_variable инициализированную значение 42:
#include <convar.h>
ConVar my_variable( "my_variable", "42", FCVAR_ARCHIVE, "Моё любимое число" );
void MyFunction_f( void )
{
Msg("Это моя функция\n");
}
ConCommand my_function( "my_function", MyFunction_f, "Выводит сообщение.", FCVAR_CHEAT );
Это обычное использование когда имя объекта и команды одинаковое и переменные используются только в одном исходнике описываются как static.
Использование класса ConVar
Для начала рассмотрим наиболее используемый ConVar конструктор:
ConVar( char const *pName,
char const *pDefaultValue,
int flags,
char const *pHelpString )
Первый аргумент pName это имя переменной (без пробелов), следующий pDefaultValue,всегда является строковым, даже для ConVar's с числовыми значениями. Flags пределяет специальные характеристики переменной, все описания флагов начинаются с FCVAR_*, но об этом позже. Очень хорошо использовать pHelpString, чтобы пользователи могли понять для чего эта переменная предназначена. ConVars не ограничиваются определненным типом, их значение может быть целым или вещественным или строкой и вы можете его использовать как вам угодно. Так долго как у вас есть ConVar объект сам или указатель на него, вы можете смотреть и изменять его значение напрямую. Все эти примеры правильны и дадут одинаковый результат:
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" );
В любое время вы можете вернуть значение [ConVar]] назад к значению по-умолчанию использовав функцию Revert().
Если 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, "справочный текст", true, 1, true, 100 );
Иногда необходимо чтобы вы получали извещение когда пользователь или другая подсистема меняет значение вашей ConVar, поэтому может быть установлена функция обратного вызова:
static void OnChangeMyVariable ( ConVar *var, char const *pOldString )
{
DevMsg( "Значение ConVar %s изменено с %s на %s\n", var->GetName(), pOldString, var->GetString() );
}
ConVar my_variable( "my_variable", "42", 0, "Моё любимое число", OnChangeMyVariable );
Использование класса ConCommand
Class ConCommand проще чем ConVar и у него только один конструктор:
ConCommand( char const *pName,
FnCommandCallback callback,
char const *pHelpString = 0,
int flags = 0,
FnCommandCompletionCallback completionFunc = 0 );
Как и у ConVar pName определяет имя команды (без пробелов!). callback эта функция выполняемая когда пользователь исполняет эту команду, pHelpString и признаки имеют те же функции, что и в ConVar. ConCommands поддерживает автозавершение для первого параметра,
особенно используемый для которые обрабатывают файлы. Например, вы используете команду loadtext lt;textfilegt; которая предполагает .txt файл для ввода, терминал ищет все доступные .txt файлы и позволяет пользователю выбрать один из списка. Если правильно, то completionFunc проходит, она вызывается каждый раз когда системе терминала требуется список доступных аргументов.
Когда callback фунция выполняется, введенные в терминале параметры не подаются как аргументы функции. callback функциям необходимо запрашивать у движка как много аргументов поступило используя функцию интерфейса движка Cmd_Argc(). Затем можно получить отдельные аргументы используя Cmd_Argv(index), где index 1 это первый аргумент. Аргументы всегда возвращаются как строки.
void MySay_f ( void )
{
if ( engine->Cmd_Argc() < 1 )
{
Msg("Синтаксис: my_say <text>\n");
return;
}
Msg("Я говорю: %s\n", engine->Cmd_Argv(1) );
}
ConCommand my_say( "my_say", MySay_f, "сказал что-то", 0);
Это пример как создать простой автозавершающийся список. Неполный параметр не используется здесь; он содержит символы введеные так давно (включая само имя команды) :
static int MySayAutoComplete ( char const *partial,
char commands[ COMMAND_COMPLETION_MAXITEвMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
{
strcpy( commands[0], "hello" );
strcpy( commands[1], "goodbye" );
return 2; // number of entries
}
ConCommand my_say( "my_say", MySay_f, "сказал что-то", 0, MySayAutoComplete);
To retrieve the calling player from a concommand, use UTIL_GetCommandClient() on the server or C_BasePlayer::GetLocalPlayer() on the client.
Команды игрока клиента
All server-side player classes derived from CBasePlayer have a function, ClientCommand, which is called when the player issues a ConCommand. This function can be used to handle concommands.
bool CHL2MP_Player::ClientCommand( const char *pcmd )
{
if ( FStrEq( pcmd, "spectate" ) )
{
if ( ShouldRunRateLimitedCommand( pcmd ) )
{
// instantly join spectators
HandleCommand_JoinTeam( TEAM_SPECTATOR );
}
return true;
}
else if ( FStrEq( pcmd, "jointeam" ) )
{
if ( engine->Cmd_Argc() < 2 )
{
Warning( "Player sent bad jointeam syntax\n" );
}
if ( ShouldRunRateLimitedCommand( pcmd ) )
{
int iTeam = atoi( engine->Cmd_Argv(1) );
HandleCommand_JoinTeam( iTeam );
}
return true;
}
else if ( FStrEq( pcmd, "joingame" ) )
{
return true;
}
return BaseClass::ClientCommand( pcmd );
}
As you can see in this example HL2MP code, the function is called with an argument, pcmd, which is then handled based on several if statements. The function ShouldRunRateLimitedCommand is used to prevent spamming and checks to make sure that the command wasn't too recently called.
This function will look slightly different in code derived from the Orangebox engine.
Признаки FCVAR
Команды и переменные управления используют признаки, которые обладают определенными характеристиками и должны обрабатываться с осторожностью. Эти признаки используются конструктором и могут быть изменены с помощью ConCommandBase::AddFlags() (не используются сильно часто). Невозможно изменить эти признаки подругому как в исходных кодах чтобы избежать читов. Некоторые признаки должны быть установлены вручную, другие устанавливаются автоматически системой терминала:
FCVAR_LAUNCHER, FCVAR_GAMEDLL, FCVAR_CLIENTDLL, FCVAR_MATERIAL_SYSTEM, FCVAR_STUDIORENDER
Эти признаки устанавливаются в процессе регистрации и указывают на модуль, где команда создана (вам не нужно устанавливать их). Следующие признаки должны быть установлены вручную:
FCVAR_CHEAT
|
Используются при отладке, не удаляются из релиза по причине того, что могут потребоваться разработчикам модов и карт. К сожелению мы неможем позволить нормальным игрокам использовать эти инструменты отладки так как это бы было нечестно по отношению к другим игрокам (читерство). Хорошее правило добавлять FCVAR_CHEAT по началу ко всем новым командам управления которые вы добавляете, если это не конечная и законная опция для игроков. Опыт показывает что даже наиболее безвредные отладочные команды могут быть использоваться тем или иным образом как чит.
Игровой сервер, устанавливая |
FCVAR_USERINFO
|
Некоторые переменные управления содержат клиентскую информацию о которой должен знать сервер, такое как имаена пользователей или их четевые настройки. Эти переменные должны быть помечены флагом FCVAR_USERINFO, тогда они будут преданы серверу и обновляться каждый раз когда пользователь изменяет их. Когда пользователь изменяет эти переменные движок оповещает серверный код с помощью ClientSettingsChanged(). Затем сервер может запросить движок отдельные клиентские настройки с помощью GetClientConVarValue().
|
FCVAR_REPLICATED
|
Игровой сервер и клиент используют общий код, поэтому важно чтобы обе стороны выполнялись по одиноковому пути используя одинаковые данные (например предсказание движения/оружий, правил игы). Если этот код использует переменные управления, они должны иметь одинаковые значения на обоих сторонах. Флаг FCVAR_REPLICATED гарантирует рассылку значений всем клиентам. Пока подключены, клиенты немогут менять эти значения так как будут использовать серверные значения.
|
FCVAR_ARCHIVE
|
Некоторые переменные управления содержат пользовательские настройки мы хотим их востанавливать кадый раз когда игра запущена ( как имя или network_rate). Если переменная управления помечена как FCVAR_ARCHIVE, она сохраняется в файл config.cfg когда игра завершается и она будет загружена при следующем запуске. (Также команда host_writeconfig сохранет все FCVAR_ARCHIVE значения в файл).
|
FCVAR_NOTIFY
|
Если переменная управления помечена как FCVAR_NOTIFY, сервер отправляет сообщение всем клиентам всякий раз когда переменная изменена. Это должно быть использовано для перменных которые меняют правила игры, которые важны для всех игроков (mp_friendlyfire например).
|
FCVAR_PROTECTED
|
Эта переменная управления содержащая частную информацию (пароль например), мы нехотим чтобы она была видна другим пользователям. Для этого должен быть установлен флаг FCVAR_PROTECTED чтобы пометить эту информацию как конфиденциальную.
|
FCVAR_SPONLY
|
Иногда исполнение команды или изменение переменной может быть правильно только в однопользовательском режиме, тогда пометьте эту команду как FCVAR_SPONLY.
|
FCVAR_PRINTABLEONLY
|
| Некоторые важные переменные тяжелые или шировещательные (например правила игры) и важно что они содержат только печатные сиволы (например нет управляющих символов). |
FCVAR_NEVER_AS_STRING
|
| Этот флаг говорит движку никогда невыводить эту переменную как строку так как она содержит последовательность управляющих символов. |
FCVAR_DEMO
|
| Когда на чинаешь записывать демо файл, некоторые переменные управления должны быть добавлены к записи, чтобы быть уверенными, что она правильна будет воспроизведена. |
FCVAR_DONTRECORD
|
| Это обратно FCVAR_DEMO, некоторые переменные управления не должны быть записаны в демо файлы. |
