Dragokas
Добрая душа
- Сообщения
- 224
- Реакции
- 206
7. Различные функции и информация:
Hammer и Authoring Tools:
- Для L4D/2 перейдите в клиент Steam > Библиотеки > Снимите галочку "Показать только готовые к запуску игры" (в старых версиях - это раздел "Инструменты"), найдите в списке и скачайте L4D/2 Authoring Tools. Он включает в себя Model Viewer (просмотрщик моделей) - полезен для определения индексов анимации и точек крепления, используемых для фишек вроде "SetParent". Вы можете распаковать модель .mdl в папку вашей игры /models/ чтобы отрыть её в этом инструменте.
- CS:GO hammer доступен только после покупки обновления с Prime статусом на странице магазина Steam. Ссылки: здесь и здесь.
- Расширение Stripper:Source- Вместо декомпиляции карты, с помощью этого инструмента можно сделать дамп данных карты и уже в нём смотреть, что и как работает.
- Я использовал это и hammer для воспроизведения через плагин различных функций, реализованных на картах для L4D2.
- Stripper также полезен для изменения сущностей на картах. Почитайте его тему для больших подробностей.
Партикли (так называемые частицы, Particles):
- В хаммере (по крайней мере в L4D2) вы можете увидеть частицы, указав их в сущности "info_particle_system", сделав двойной клик на "Particle System Name" в списке keyvalues. Это откроет "Браузер частиц". Редактор частиц доступен через "L4D Authoring Tools" -> L4D (Tools Mode).
- Также есть [Batch] Пакетный распаковщик частиц & плагин тестирования и руководство от Dragokas.
- Некоторые или большинство из игр на движке source также включают внутри-игровой Редактор частиц (см. по ссылке, как его включить), полезен для отображения и создания сторонних частиц. Вы можете воспользоваться функцией SourceMod-а AddFileToDownloadsTable для передачи клиентам сторонних моделей, звуков, частиц и т.д.
- Чтобы пре-кешировать частицы используйте следующий stock и вызывайте его в OnMapStart();
PHP:
public void OnMapStart()
{
PrecacheParticle("flare_burning");
}
int PrecacheParticle(const char[] sEffectName)
{
static int table = INVALID_STRING_TABLE;
if( table == INVALID_STRING_TABLE )
{
table = FindStringTable("ParticleEffectNames");
}
int index = FindStringIndex(table, sEffectName);
if( index == INVALID_STRING_INDEX )
{
bool save = LockStringTables(false);
AddToStringTable(table, sEffectName);
LockStringTables(save);
index = FindStringIndex(table, sEffectName);
}
return index;
}
AddFileToDownloadsTable: (сторонний контент)
- Функция AddFileToDownloadsTable позволяет вам отправлять сторонние файлы клиентам.
- Вам необходимо это делать в OnMapStart и обязательно пре-кешировать контент, к примеру, с помощью PrecacheModel, PrecacheSound, PrecacheGeneric и других Precache* функций.
- Есть несколько плагинов, которые позволяют это делать автоматически:
- [ANY] EasyDownloader
- [ANY] Auto File Loader (Automatic Precaching/Downloads)
- SM File/Folder Downloader and Precacher
- L4D и L4D2 имеют проблемы, вызывающие эффект чёрного экрана в процессе загрузки контента. Возможный фикс: Black Screen Fix aka Delayed downloader
Свойства сущности: (Prop_Data и Prop_Send)
- NetProps и DataMaps являются игровыми переменными, используемыми сущностями для хранения данных о себе. NetProps передаются клиентам, тогда как DataMaps доступны только для сервера.
- Их можно читать с помощью: GetEntProp, GetEntPropArraySize, GetEntPropEnt (для получения сущности или индекса клиента из свойства сущности), GetEntPropFloat, GetEntPropFloat, GetEntPropVector и изменять через соответствующие SetEntProp* функции. HasEntProp позволит вам проверить, существует ли у сущности указанное вами имя свойства.
- SourceMod предоставляет несколько команд для сбора полезной информации. Чтобы просмотреть полный список, введите find sm_dump в консоль сервера.
- Введите следующие команды в вашу серверную консоль для генерации и сохранения отчётов в корневую папку игры (рядом с addons, bin, cfg, maps):
- Команды для дампа всех свойств netprops и datamaps у всех сущностей:
- Формат лога "datamaps": "имя свойства" ("смещение") ("тип") ("размер") - "KeyValue" (применяется в функциях DispatchKeyValue*).
sm_dump_netprops_xml netprops.xml
sm_dump_netprops netprops.txt
sm_dump_datamaps datamaps.txt - Имена классов сущностей выводятся в формате: серверное имя класса (GetEntityNetClass) - имя класса сущности (GetEdictClassname).
sm_dump_classes classes.txt - Список временных сущностей (TempEnts) и их формат.
sm_dump_teprops teprops.txt
События:
- Игра возбуждает события, которые затем плагины могут перехватить (хукнуть) для выполнения различных задач, когда наступают специфические условия, вызывающие эти события.
- Events (SourceMod Scripting) - Подробности о том, как искать, хукать, создавать, блокировать и изменять события.
- Game Events (Source) - Список разнообразных событий, общих и специфических для конкретной игры событий (Некоторые данные могут отсутствовать или быть устаревшими).
- Вы можете воспользоваться GCFScape, чтобы открыть ваши игровые файлы .VPK и извлечь оттуда различные .res файлы для поиска событий ("events") в папке resource.
Звуковые хуки:
- Звуковые хуки могут изменять громкость, воспроизводимый файл или блокировать звуки.
PHP:
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
bool g_bBlockSound;
public void OnPluginStart()
{
// ПРЕДУПРЕЖДЕНИЕ: Избегайте хука более, чем один раз, хукайте только единожды.
// Вы можете, к примеру, использовать статический или глобальный bool, допустим g_bHooked, чтобы избежать множественный хуков звука.
// Вы можете хукать, где угодно. Хук не обязательно должен быть в OnPluginStart.
// Большинство звуков воспроизводятся через это:
AddNormalSoundHook(SoundHook);
// Однако, некоторые звуки могут воспроизводиться только здесь:
AddAmbientSoundHook(AmbientHook);
}
public void OnPluginEnd()
{
// Вам не нужно снимать хук в OnPluginEnd, просто показываю, что вы можете это сделать, если вам больше не нужен хук.
RemoveNormalSoundHook(SoundHook);
RemoveAmbientSoundHook(AmbientHook);
}
// Слежение за броском гранат.
public void OnEntityCreated(int entity, const char[] classname)
{
if( strncmp(classname, "molotov_projectile", 13) == 0 )
{
SDKHook(entity, SDKHook_SpawnPost, SpawnPost);
}
}
public void SpawnPost(int entity)
{
RequestFrame(OnNextFrame);
g_bBlockSound = true;
}
public void OnNextFrame()
{
g_bBlockSound = false;
}
public Action SoundHook(int clients[MAXPLAYERS], int &numClients, char sample[PLATFORM_MAX_PATH], int &entity, int &channel, float &volume, int &level, int &pitch, int &flags, char soundEntry[PLATFORM_MAX_PATH], int &seed)
{
// Поскольку SoundHook вызывается для каждого воспроизводимого звука, лучше всего избегать сравнения строки, на сколько это возможно
if( g_bBlockSound )
{
// Блокируем звук, когда бросается молотов
if( strcmp(sample, "weapons/molotov/fire_loop_1.wav") == 0 )
{
return Plugin_Handled;
}
}
// Уменьшаем громкость взрыва
if( strcmp(sample, "weapons/molotov/molotov_detonate_3.wav") == 0 )
{
volume = 0.5;
return Plugin_Changed;
}
// Без изменений
return Plugin_Continue;
}
public Action AmbientHook(char sample[PLATFORM_MAX_PATH], int &entity, float &volume, int &level, int &pitch, float pos[3], int &flags, float &delay)
{
// Тоже самое, что и выше, только для звуков окружения (Ambient Sounds).
}
SetTransmit: (Прячет модели от отдельных игроков):
- SDKHook_SetTransmit может быть использован, чтобы спрятать от клиентов модели, частицы и некоторые другие типы сущностей (например, light_dynamic).
- Попытка спрятать частицы может не сработать в некоторых играх или например, может сработать только на Windows. Это ограничения движка.
- Попытка спрятать некоторые сущности может не сработать, например, prop_glowing_object в L4D1.
- Инфа от asherkin: CBaseEntity::SetTransmit является очень горячей функцией, поэтому у движка есть множество оптимизаций, чтобы предотвращать излишние её вызовы. Обычно, по этому пути идут сущности с флагами FL_EDICT_FULLCHECK, FL_EDICT_ALWAYS и FL_EDICT_PVSCHECK. Для полного понимания, можно обратиться к ключевой логике в CServerGameEnts::CheckTransmit из SDK.
- Два примера, для пропов и частиц:
Модели:
PHP:
bool g_bShowProp[MAXPLAYERS+1];
public Action CmdProp(int client, int args)
{
// Предположим, что мы создали сущность "prop", но нам хочется показать её только конкретным клиентам
int entity = CreateEntityByName("prop_dynamic");
// Остальные вещи для сущности. SetEntityModel() и т.д. Опускаем здесь, для краткости примера.
// Теперь мы хукаем её. Функция обратного вызова (колбэк) Hook_SetTransmit вызывается с каждым фреймом, поэтому здесь внутри лучше использовать простые расчёты
SDKHook(entity, SDKHook_SetTransmit, Hook_SetTransmit);
// Существуют разные способы, чтобы это сделать. Советую посмотреть другие плагины в качестве примеров.
// Мы собираемся сохранить здесь значение, чтобы определять, можно ли клиенту видеть сущность или нет.
g_bShowProp[client] = true;
}
public Action Hook_SetTransmit(int entity, int client)
{
// Проверяем, разрешено ли клиенту видеть сущность
if( g_bShowProp[client] == true )
return Plugin_Continue; // Это разрешит сущности быть видимой для клиента.
return Plugin_Handled; // Это спрячет её от клиента, если клиенту не разрешается видеть её.
}
Частицы:
PHP:
bool g_bShowProp[MAXPLAYERS+1];
public Action CmdProp(int client, int args)
{
// Предположим, мы создали частицу, но желаем отобразить её только для конкретных игроков
int entity = CreateEntityByName("info_particle_system");
// Остальные свойства сущности. DispatchSpawn() и т.д. Опускаем, чтобы сократить пример.
SDKHook(entity, SDKHook_SetTransmit, Hook_SetTransmit);
g_bShowProp[client] = true;
}
public Action Hook_SetTransmit(int entity, int client)
{
// Проверка, позволено ли клиенту видеть проп
if( g_bShowProp[client] == true )
return Plugin_Continue; // Это разрешит пропу быть видимым для клиента
// Следующие две строки используются, чтобы прятать частицу
// Это, вероятно, может заработать только в конкретных играх, либо только на серверах Windows
if( GetEdictFlags(entity) & FL_EDICT_ALWAYS )
SetEdictFlags(entity, GetEdictFlags(entity) &~ FL_EDICT_ALWAYS);
return Plugin_Handled;
}
RequestFrame: (выполнение кода с задержкой времени на 1 фрейм)
- CreateTimer() имеет минимальное значение в 0.1 секунду. Для всего, что быстрее (например, следующий фрейм игры) лучше использовать RequestFrame().
- Когда вы определяете снаряды (projectiles) в OnEntityCreated() и используете SDKHook_SpawnPost(), данные о скорости здесь всё ещё не инициализированы. Вот где я использую RequestFrame() для получения действительных данных.
PHP:
// Слежение за броском гранат
public void OnEntityCreated(int entity, const char[] classname)
{
if( strcmp(classname, "molotov_projectile") == 0 )
{
// Ждем, пока сущность полностью заспавнится (появится)
SDKHook(entity, SDKHook_SpawnPost, SpawnPost);
}
}
public void SpawnPost(int entity)
{
// 1 фрейм требуется для получения скорости
RequestFrame(OnNextFrame, EntIndexToEntRef(entity));
}
public void OnNextFrame(int entity)
{
// Верифицируем сущность
if( EntRefToEntIndex(entity) == INVALID_ENT_REFERENCE || !IsValidEntity(entity) )
return;
// Теперь скорость действительна и не равна 0,0,0
float vPos[3];
GetEntPropVector(entity, Prop_Send, "m_vInitialVelocity", vPos);
}
- Переключение игроков в команду Зрителей сразу же после подключения. Это предотвращает от каких-либо задержек, из-за которых их могло бы успеть заспавнить сперва где-либо ещё (спасибо "Maxximou5" и "Desktop" за пример):
PHP:
#include <cstrike>
public void OnPluginStart()
{
HookEvent("player_connect_full", Event_PlayerConnectFull);
}
public void Event_PlayerConnectFull(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
RequestFrame(Frame_ChangeTeam, client);
}
public void Frame_ChangeTeam(any client)
{
ChangeClientTeam(client, CS_TEAM_SPECTATOR);
}
Разное:
- Цвет текста (инклуды): Colors.inc, stamm-colors.inc, morecolors.inc, multicolors.inc, colorvariables.inc, colorsLib.inc
- SteamID типы: Steam2, Steam3 & Steam64. Используйте GetClientAuthId для получения нужного вам типа. Хороши для хранения в файл/базе данных для восстановления после перезагрузки. Прим. переводчика: GetClientAuthId может вернуть вместо SteamId строку "STEAM_ID_STOP_IGNORING_RETVALS" в случае, когда сеть Steam недоступна, или клиент не успел авторизоваться.
- KeyValue конфиги - Они необходимы для многих вещей. Настройки данных, чтение, сохранение. Например, KeyValues SourceMod Scripting.
- SMCParser - Подобны KeyValue конфигам, но не требуют заранее знать имя ключа. Примеры см. в папке со скриптами SM scripting/admin-flatfile. Или в моих VScript Replacer, Info Editor или Neon Beams, как наиболее простая версия. Прим. переводчика: является более надёжным инструментом, совместим с форматом KeyValues файлов, но в отличии от последнего поддерживает многострочные комментарии).
- Client Preferences (предпочтения клиента) - это куки, которые используются для хранения клиентских данных. [Tutorial] ClientPrefs. Хранение простых настроек для каждого из клиентов. Прим. переводчика: по своей сути представляют из себя записи в базе данных, хранящейся на сервере (файл data/sqlite/clientprefs-sqlite.sq3). Максимальная длина строки данных, которую можно записать с помощью хендла куки = 100 байт.
- GCFScape - Для открытия VPK и получения файлов, к примеру "modevents.res" в качестве источника для событий, используемых игрой (другие источники по большей части устарели). Также для открытия .BSP и извлечения ресурсов карты.
- VProf - Для проверки производительности плагинов. Используйте только в тестовой среде, а не на живом сервере, т.к. эта проверка может быть слишком интенсивной.
- SM profiler API - Для запуска проверок скорости работы (бенчмаркинга) определённых участков вашего плагина.
- Timers - Можно использовать для задержки задач, например, сообщений с приветствием, или для повторения чего-либо несколько раз в течении определённого интервала. См. сообщение со множеством примеров правильного использования.
- Translations - Используется для многоязычной поддержки, когда на экран отображаются сообщения или перевод в менюшках и пр.
Информация:
- edict могут иметь индексы только в пределах от 0 до 2048. Больше 2048 имеют не передающиеся по сети сущности (non-networked entities), которые может увидеть только сервер (например, сущность logic_case).
- Новые игры имеют более высокие лимиты.
- CS:GO может использовать до 4096 под edicts (Я предполагаю, что 4097 - 8192 - выделены для не передающихся по сети сущностей).
- Garrys Mod очевидно поддерживает до 8192 под edict-ы.
- IsValidEdict() возвращает false для non-networked сущностей. Для таких, используйте IsValidEntity().
- FindEntityByClassname() для non-networked сущностей возвращает ссылку на сущность (к примеру, номер сущности будет чем-то вроде: -2036529131).
- Вы можете преобразовать её обратно в индекс сущности с помощью EntRefToEntIndex() и получить значение между 2049-4096. Однако, если вы не планируете использовать его в качестве индекса для массива, то лучше ограничиться использованием ссылки. - Format - Используйте при форматировании строки, когда буфер назначения является также одним из параметров.
PHP:Format(buffer, sizeof buffer, "%i %s", someInt, buffer);
- FormatEx - Используйте, когда форматируемый и целевой буферы НЕ совпадают (она быстрее чем Format).
PHP:FormatEx(buffer, sizeof buffer, "%i", someInt);
- strcopy - Используйте для копирования строки, не использующей правила форматирования.
PHP:strcopy(buffer, sizeof buffer, "Some string");
- StrCat - Используйте для добавления в конец целевой строки, без необходимости в форматировании.
PHP:StrCat(buffer, sizeof buffer, "this text is appended to buffer");
- net_showevents 2 - отобразит на серверной консоли все игровые события
- report_entities - считает кол-во одинаковых классов энтити на карте и выводит отчёт в серверную консоль
- cl_showents клиентский квар - выводит список сущностей и их индексы (требует sv_cheats 1).
- cl_showpos 1 клиентский квар - для открытия мини-панели, отслеживающей вашу текущую позицию, угол, скорость.
- +posedebug клиентский квар - показывает имена поз / анимаций.
- soundinfo - отображает список звуков, которые воспроизводятся в данный момент.
- listmodels - список моделей на этой карте.
- net_graph клиентский квар - позволяет вам увидеть графики fps, ping, lerp, нагрузку на сеть и т.п. Больше инфы.
- net_graph 4 - рекомендован.
- Вот примеры биндов, которые я использую. Когда нажимаешь на Tab для открытия табло с игроками, то одновременно отображается и net_graph:
PHP:bind tab +tabscore; alias +tabscore "+showscores; net_graph 4"; alias -tabscore "-showscores; net_graph 0"; net_graphpos 0 // default 1; Left = 0; Right = 1; Centre = 2
- Клиентские квары для симуляции лагов (можно использовать для тестов). Требуется включённый sv_cheats:
- net_fakejitter - фейковые колебания пинга (Jitter)
- net_fakelag - лаг для всех входящий сетевых данных (включая петлю) на указанное кол-во миллисекунд.
- net_fakeloss - Симулировать потерю пакетов в процентах (негативное число означает потерю 1/n пакетов)
- net_droppackets - Потерять следующие N пакетов у клиента
- net_chokeloop - Применить колебание на полосе пропускания для петлевых пакетов
- sv_allow_wait_command - Серверный квар, разрешающий или запрещающий команду wait для клиентов, подключённых к серверу.
- Это приведет к вылету клиента, если он однажды использовал команду wait, а сервер отключил её без перезапуска игры клиентом. - developer 1 - клиентская команда, печатает более подробную инфу; полезен для отладки. Пример: отслеживание изменения кваров.
Последнее редактирование: