Большая часть функциональности игровых DLL определяется функциями, предоставляемыми движком игры. Чтобы создавать собственные объекты и эффекты, вам необходимо хорошо в них разбираться. В этой статье я хочу рассмотреть функции серверной DLL, которые могут быть вам полезны – для чего они нужны и как им применять. Все функции движка находятся в структуре enginefuncs_t, которая передается в DLL в функции GiveFnptrsToDll (“Give function pointers to DLL”). Она вызывается движком сразу после инициализации библиотеки и заполняет локальную копию структуры – переменную g_engfuncs. Вы можете вызывать эти функции двумя способами: 1) Прямой вызов по указателю, например: g_engfuncs. pfnMessageEnd(); 2) Вызов при помощи макроса или инлайн-функции, предопределенных в файле enginecallback.h, например: MESSAGE_END(); Последний способ предпочтительнее, т.к. позволяет более гибко передавать параметры, например, использовать параметры по умолчанию. Впрочем, если вы в этом пока не очень хорошо разбираетесь, просто используйте второй способ. Я же буду приводить синтаксис вызова для обоих вариантов – название для первого и псевдоним для второго. Хотелось бы сразу устранить некоторую путаницу со строками. В серверной части игры часто строки хранятся как целочисленные смещения (string_t), а функции движка работают только с массивами символов (char*). Поэтому string_t нужно преобразовать к char* вот таким способом:
char *pszTarget = const_cast<char*>(STRING(pev->target));
Таким образом, если вы получаете ошибку компиляции вида «cannot convert parameter 1 from 'int' to 'char *'», вам нужно сделать это преобразование. Вы привыкли работать с классами, а функции движка понимают только edict_t* в качестве ссылки на энтити. Тут преобразование просто: 1) Из указателя на класс: edict_t *pEdict = pMyClass->edict(); 2) Из pev класса: edict_t *pEdict = ENT(pev); Некоторые функции записывают свои значения по указателям, переданным в качестве параметров. Например, векторы записываются в указатель на массив float. Вам нужно самим проследить, что вы передали правильные параметры! Например, если функция заполняет вектор, то выглядеть вызов будет так:
float flVec[3]; MyFunctionThatFillsVector(flVec); //или MyFunctionThatFillsVector(&flVec[0]); Vector vVec = Vector(flVec);
И с vVec вы уже можете работать, как привыкли.
Итак, переходим к рассмотрению самих функций.
Список описанных функций:
pfnPrecacheModel pfnPrecacheSound pfnPrecacheGeneric pfnSetModel pfnModelIndex pfnModelFrames pfnSetSize
Название: pfnPrecacheModel Псевдоним: PRECACHE_MODEL Синтаксис: int PRECACHE_MODEL(char* s); Эта функция загружает модель или спрайт в память и возвращает его индекс. Если модель не найдена, сервер отключит вас с ошибкой. Параметр s – имя модели или спрайта, например, “models/player.mdl”. Прежде чем использовать модель или спрайт в игре, их необходимо прекэшировать. Эта функция может быть вызвана только в функции Spawn класса (хотя ее обычно выносят в отдельную функцию Precache, чтобы ресурсы кэшировалась также после загрузки сохраненной игры, когда Spawn не вызывается).
Название: pfnPrecacheSound Псевдоним: PRECACHE_SOUND Синтаксис: int PRECACHE_SOUND(char* s); Эта функция загружает звук в память (производя при необходимости конвертацию в поддерживаемый формат, если это возможно) и возвращает его индекс. Если звук не найдет, сервер создаст пустой звук. Параметр s – имя звукового файла, например, “common/null.wav”. Прежде чем использовать звук в игре, его необходимо прекэшировать. Ограничения на вызов те же, что и у pfnPrecacheModel (см. выше).
Название: pfnPrecacheGeneric Псевдоним: PRECACHE_GENERIC Синтаксис: int PRECACHE_GENERIC(char* s); Эта функция проверяет наличие произвольного ресурса, загружает его и возвращает его индекс. Зачем этот индекс может понадобиться, знают только разработчики... А польза от функции в том, что при сетевой игре, если файл отсутствует у клиента, он будет ему закачан с сервера, и клиентская DLL сможет получить к нему доступ. Ограничения на вызов те же, что и у pfnPrecacheModel (см. выше).
Название: pfnSetModel Псевдоним: SET_MODEL Синтаксис: void SET_MODEL(edict_t *e, const char *m); Устанавливает модель или спрайт для энтити. Ресурс должен быть прекэширован (при помощи PRECACHE_MODEL). Первый параметр – энтити (как правило, текущая, так что можете написать ENT(pev), второй – название модели (такое же, как в PRECACHE_MODEL, только для преобразования из string_t достаточно просто STRING, без const_cast’а).
Название: pfnModelIndex Псевдоним: MODEL_INDEX Синтаксис: int MODEL_INDEX(const char *m); Возвращает индекс модели или спрайта (тот же, что и функция PRECACHE_MODEL). Параметр – имя модели (см. pfnSetModel).
Название: pfnModelFrames Псевдоним: MODEL_FRAMES Синтаксис: int MODEL_FRAMES(int modelIndex); Функция работает со спрайтами и возвращает количество кадров анимации в них. Параметр – индекс спрайта, возвращаемый функциями PRECACHE_MODEL или MODEL_INDEX. Если была вызвана SET_MODEL, то для текущего спрайта вы также можете использовать pev->modelindex.
Название: pfnSetSize Псевдоним: SET_SIZE Синтаксис: void SET_SIZE(edict_t *e, const float *rgflMin, const float *rgflMax); Устанавливает размер Bounding Box энтити (ее размер для проверки столкновений и пересечений). Первый параметр – минимумы по X,Y и Z, второй – максимумы; они задаются в относительных координатах. Удобнее, однако, использовать функцию UTIL_SetSize:
void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax );
Пример вызова: UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); Так задается размер 16х16х16 для текущей энтити. Ее центр окажется в центре коробки (центр – это точка (0, 0, 0) в относительных координатах).
pfnChangeLevel pfnGetSpawnParms pfnSaveSpawnParms pfnVecToYaw pfnVecToAngles pfnMoveToOrigin pfnChangeYaw pfnChangePitch pfnGetEntityIllum
Название: pfnChangeLevel Псевдоним: CHANGE_LEVEL Синтаксис: void CHANGE_LEVEL(char* s1, char* s2); Осуществляет смену уровня (см. trigger_changelevel). Первый параметр – имя нового уровня, второй – имя ландмарка (info_landmark). Тут есть одна тонкость – чтобы правильно вычислить относительные координаты игрока по отношению к ландмарку нового уровня (абсолютные-то другие!), нужно сохранить положение ландмарка на текущем уровне в переменную gpGlobals->vecLandmarkOffset.
Название: pfnGetSpawnParms Псевдоним: GET_SPAWN_PARMS Синтаксис: void GET_SPAWN_PARMS(edict_t *ent); О назначении этой функции можно лишь догадываться. В Quake существовал набор 16 уникальных значений, закрепленных за клиентом – spawn_parms. Они хранились в структуре движка, но могли передаваться в progs.dat для обработки. В Half-Life это, похоже, было упразднено. Таким образом, данная функция не используется.
Название: pfnSaveSpawnParms Псевдоним: SET_SPAWN_PARMS Синтаксис: void SET_SPAWN_PARMS(edict_t *ent); Как и pfnGetSpawnParms, эта функция не используется в Half-Life.
Название: pfnVecToYaw Псевдоним: VEC_TO_YAW Синтаксис: float VEC_TO_YAW(const float *rgflVector); Возвращает yaw-компонент угла (поворот относительно оси oZ), в который конвертируется вектор rgflVector. Сам вектор – обычно разность конечной и начальной точек. Удобнее использовать функцию UTIL_VecToYaw:
float UTIL_VecToYaw( const Vector &vec );
Пример: вы хотите сделать голограмму, которая всегда повернута к игроку. Допустим, у вас есть указатель на класс игрока и функция CMyHologram::Think, вызываемая каждые 0.1 с. Тогда код будет выглядеть так:
pev->angles.y = UTIL_VecToYaw(m_pPlayer->pev->origin – pev->origin);
Название: pfnVecToAngles Псевдоним: VEC_TO_ANGLES Синтаксис: void VEC_TO_ANGLES(const float *rgflVectorIn, float *rgflVectorOut); Более общая функция, чем pfnVecToYaw: она также вычисляет pitch и roll-компоненты угла, иными словами, полное значение угла. Сам вектор – обычно разность конечной и начальной точек. Удобнее использовать функцию UTIL_VecToAngles:
Vector UTIL_VecToAngles( const Vector &vec );
В вышеупомянутом примере можно заставить модель вести себя подобно спрайту, то есть поворачиваться к игроку всегда «лицом»:
pev->angles = UTIL_VecToAngles(m_pPlayer->pev->origin – pev->origin);
Название: pfnMoveToOrigin Псевдоним: MOVE_TO_ORIGIN Синтаксис: void MOVE_TO_ORIGIN(edict_t *ent, const float *pflGoal, float dist, int iMoveType); Эта функция заставляет монстров ходить и летать. Первый параметр – edict монстра, второй – массив из трех значений с плавающей точкой – координаты точки, куда надо переместиться. Третий – размер «шага» монстра, т.е. на сколько его нужно переместить в заданном направлении. Обычно для наземных монстров это значение не превышает 16, иначе будут проблемы со ступеньками лестниц. Последний параметр – тип перемещения. Он может быть равен MOVE_NORMAL (монстр идет туда, куда смотрит, при необходимости поворачиваясь – характерно для наземных) или MOVE_STRAFE (монстр не поворачивается – характерно для летающих). Удобнее использовать функцию UTIL_MoveToOrigin:
void UTIL_MoveToOrigin( edict_t *pent, const Vector &vecGoal, float flDist, int iMoveType );
Название: pfnChangeYaw Псевдоним: - Синтаксис: void g_engfuncs.pfnChangeYaw (edict_t* ent); Эта функция изменяет yaw-компонент угла энтити следующим образом: приближает значение pev->angles.y к pev->ideal_yaw со скоростью pev->yaw_speed и приводит угол в диапазон 0..360. Ничего особо оригинального, в Half-Life это делается в функции CBaseMonster::ChangeYaw. Эта функция досталась нам в наследство от Quake, где был интерпретируемый код и все часто вызываемые функции старались сделать частью движка, а не progs.dat.
Название: pfnChangePitch Псевдоним: CHANGE_PITCH Синтаксис: void CHANGE_PITCH(edict_t* ent); Аналогично pfnChangeYaw, функция изменяет pitch-компонент угла энтити следующим образом: приближает значение pev->angles.x к pev->idealpitch со скоростью pev-> pitch_speed и приводит угол в диапазон 0..360. В Half-Life эта функция, как и значения pev->idealpitch и pev->pitch_speed, не используется.
Название: pfnGetEntityIllum Псевдоним: GETENTITYILLUM Синтаксис: int GETENTITYILLUM(edict_t* pEnt); Очень интересная функция – возвращает освещенность данной энтити. Освещенность берется из лайтмапы под энтитей или над энтитей (если указан эффект EF_INVLIGHT). Значение лежит в интервале от 0 (полная темнота) до 255 (абсолютно яркая лайтмапа). Это может не работать для энтитей с невидимыми моделями (например, для игрока всегда возвращается значение 0). Если вы хотите определять освещенность игрока, вам нужно будет сделать энтитю, которая будет «привязана» к нему (постоянно перемещаться с игроком) и брать ее уровень освещенности (в качестве модели удобно использовать пустышку – модель без полигонов). В классе CBaseEntity есть перегружаемая функция Illumination, и лучше использовать ее (например, для игрока к этому значению прибавляется яркость вспышки, если игрок стреляет).
Название: pfnSetClientMaxspeed Псевдоним: - Синтаксис: void g_engfuncs.pfnSetClientMaxspeed(const edict_t *pEdict, float fNewMaxspeed); Эта функция позволяет установить максимальную скорость для одного конкретного игрока. Первый параметр – его edict, второй – значение максимальной скорости. Если указать 0, то будет установлено значение по умолчанию (задаваемое переменными sv_maxspeed и/или cl_forwardspeed).
Название: pfnGetGameDir Псевдоним: GET_GAME_DIR Синтаксис: void GET_GAME_DIR(char *szGetGameDir); Эта функция служит для получения игровой директории мода. Параметр – адрес массива символов, в который запишется путь (убедитесь, что он достаточного размера). Пример:
char szDirName[MAX_PATH]; GET_GAME_DIR( szDirName ); //или GET_GAME_DIR( &szDirName[0] );
Например, если вы запускаете мод mymod, то в переменной szDirName будет путь вида «C:\Games\Half-Life\mymod».
Источник: http://www.hlfx.ru/forum/showthread.php?s=08077d3c0f5c95eb3c499ca8c7341ced&threadid=575 |