Управление терминалом разработчика

From Valve Developer Community
< Ru
Jump to navigation Jump to search
English (en)Deutsch (de)Русский (ru)中文 (zh)Translate (Translate)
Терминал разработчика

Этот документ объясняет, как писать код, выводящий текст в терминал(en), а также, как исполнять и создавать команды и переменные управления. Смотрите Терминал разработчика(en) для обзора возможностей терминала.

Печать в терминал

Ввод текста в терминал доступен из всех модулей и контролируется через 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.

Note.pngПримечание: There exist versions of these functions which have an additional parameter called level. If level is higher than the developer cvar setting, the message will not be printed in the console. This allows you to print extended debug info only when developer mode is at a certain setting. See Developer for more info on which levels print what kind of information.

Установка значений переменных

[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.

Note.pngПримечание: You can't pass dynamic arguments to these functions. All parameters are decided when the code compiles.

Добавление новых команд и переменных

Терминал разработчика - это подсистема движка Source, которая дает доступ к различным модулям, это осуществляется через интерфейс ICvar ( см. \public\icvar.h). Этот интерфейс регистрирует новые команды и ищет существующие. Этот интрефейс доступен через глобальную переменную ConVar(en) в клиент-серверном коде (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(en) конструктор:

ConVar( char const *pName,
  char const *pDefaultValue,
  int flags,
  char const *pHelpString )

Первый аргумент pName это имя переменной (без пробелов), следующий pDefaultValue,всегда является строковым, даже для ConVar(en)'s с числовыми значениями. Flags пределяет специальные характеристики переменной, все описания флагов начинаются с FCVAR_*, но об этом позже. Очень хорошо использовать pHelpString, чтобы пользователи могли понять для чего эта переменная предназначена. ConVar(en)s не ограничиваются определненным типом, их значение может быть целым или вещественным или строкой и вы можете его использовать как вам угодно. Так долго как у вас есть ConVar(en) объект сам или указатель на него, вы можете смотреть и изменять его значение напрямую. Все эти примеры правильны и дадут одинаковый результат:

if ( my_variable.GetInt() == 42 ) DoSomething();
if ( my_variable.GetFloat() == 42.0f ) DoSomething();
if ( strcmp(my_variable.GetString(), "42")==0 ) DoSomething();

Для установки значения ConVar(en) вы должны использовать функцию SetValue(), использующая любые типы данных:

my_variable.SetValue( 42 );
my_variable.SetValue( 42.0f );
my_variable.SetValue( "42" );

В любое время вы можете вернуть значение [ConVar]] назад к значению по-умолчанию использовав функцию Revert().

Если ConVar(en) создан в разных модулях, то в интерфейсе ICvar функция FindVar()спользуется для получения указателя на объект, если имя переменной установлено. Вот простой пример, который проверяет установлена ли ConVar(en) sv_cheats(en) определенная в модуле движка:

ConVar *pCheats  = cvar->FindVar( "sv_cheats" );

    if ( pCheats && pCheats->GetInt() == 1 ) AllowCheating();

Диапозон правильных значений может быть определен для числовых ConVar(en)s используя другой конструктор. Тогда ConVar(en) автоматически проверяется системой терминала всякий когда она изменяется вручную. Если введенное число выходит за границы диапозона, оно округляется к следующему правильному значению. Установка диапозона правильных значений от 1 до 100:

ConVar my_variable( "my_variable", "42", 0, "справочный текст", true, 1, true, 100 );

Иногда необходимо чтобы вы получали извещение когда пользователь или другая подсистема меняет значение вашей ConVar(en), поэтому может быть установлена функция обратного вызова:

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 по началу ко всем новым командам управления которые вы добавляете, если это не конечная и законная опция для игроков. Опыт показывает что даже наиболее безвредные отладочные команды могут быть использоваться тем или иным образом как чит.

Игровой сервер, устанавливая sv_cheats, решает разрешены читы или нет. Если клиент подключился к серверу, где читы запрешены (должны быть по умолчанию), всем клиентским переменным управления, помеченным как 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, некоторые переменные управления не должны быть записаны в демо файлы.