Плагины для джаза могут значительно расширить его функционал, вносить изменения в геймплей и т.п., но только со стороны сервера. Для начала создания плагина вам необходимы некоторые исходники. Архив можно скачать здесь. Он содержит все игровые библиотеки, необходимые для всех создаваемых плагинов. Распакуйте эти файлы в папку include вашего компилятора. Правда, есть некоторые проблемы с компилированием под линукс с асм-вставками - включите интеловские вставки. Кроме того, необходим заголовочный файл интерфейса, который может изменяться в зависимости от версии джаза. Соответствующий вашей версии интерфейс можно найти здесь. Далее вам понадобится основа для создания плагина - ее можно скачать здесь. В ней даны все необходимые комментарии, здесь же я опишу основные функции. Движок и мод обмениваются командами, формально состоящие из 12-13 целочисленных переменных. Однако, пусть это не введет вас в заблуждение - на самом деле эти цифры могут быть чем угодно, обычно указателями. Первая цифра определяет передаваемую команду (все команды описаны в g_public), остальные могут означать что угодно.
Основные функции, предоставляемые джазом (подробнее о них можно узнать в файле jassapi.h):
JASS_WRITEGAMELOG (char * text) - запись в логи игры. Аналогично g_syscall(G_FS_WRITE, char * text, int len, JASS_GETLOGHANDLE()). Символ \n в конце необходим. JASS_WRITEJASSLOG (char * text) - запись в логи джаза. Символ \n в конце необходим. JASS_VARARGS (char * text, ...) - позволяет генерировать строки, к примеру JASS_VARARGS("Say %s","Hi") - возвратит строку "Say Hi". Действует наподобие sprintf, только не записывает в какой-то буфер, а возвращает указатель на строку. JASS_ENGMSGNAME(int cmd), JASS_MODMSGNAME(int cmd) - преобразует ID команды в строку с именем этой команды, и возвращает указатель на неё. JASS_GETINTCVAR(char * cvarname) - возвращает число, хранящийся в кваре игры. JASS_GETSTRCVAR(char * cvarname) - возвращает указатель на строку, хранящуюся в кваре игры. JASS_GETHOMEPATH - возвращает путь до папки с игрой на linux-платформах JASS_GETPLUGINID - возвращает ID плагина по имени. JASS_GETPLUGININFO - возвращает иформацию о плагине по ID JASS_PLUGINCALL - вызов функции JASS_pluginCall плагина. Первый параметр - ID, остальные - параметры функции. Возврат результата: JASS_RET_IGNORED(int x) - передает команду дальше, в мод или движок. JASS_RET_SUPERCEDE(int x) - блокирует команду.
Список основных команд из мода (подробнее в g_public.h):
GAME_INIT, // ( int levelTime, int randomSeed, int restart ) - Команда, означающая инициализацию игры. GAME_SHUTDOWN, // (void); - Команда, означающая выключение игры. GAME_CLIENT_CONNECT, // ( int clientNum, qboolean firstTime, qboolean isBot ); - Команда, означающая присоединение игрока. Возвращает 0, если игрок может присоединиться, иначе возвращает текстовую строку с причиной запрета. GAME_CLIENT_BEGIN, // ( int clientNum ); - означает, что игрок подсоединился. GAME_CLIENT_USERINFO_CHANGED, // ( int clientNum ); - означает, что игрок изменил свою информацию. GAME_CLIENT_DISCONNECT,// ( int clientNum ); - игрок отсоединен. GAME_CLIENT_COMMAND, // ( int clientNum ); - игровая команда игрока (доступ к команде через G_ARGV и G_ARGC). Помните, что джаз работает со стороны сервера, поэтому новые игровые команды создать не удастся. Работать они будут, но у игрока автодополнение работать не будет, или даже будет портить команду. Чтобы команда не портилась, вводите в консоли cmd CMD_NAME GAME_CLIENT_THINK,// ( int clientNum ); - вызывается на каждое действие игрока GAME_RUN_FRAME,// ( int levelTime ); - Фрейм. Каждый кадр на сервере является фреймом. Стандартно 20 фреймов в секунду. GAME_CONSOLE_COMMAND,// ( void ); - команда сервера или команда игрока через rcon (доступ к команде через G_ARGV и G_ARGC).
Список основных команд из движка (подробнее в g_public.h):
G_PRINT, // ( const char *string ); - сообщение в консоли сервера. G_ERROR, // ( const char *string ); - ошибка! G_MILLISECONDS, // ( void ); - Взять время с начала игры в мс. G_CVAR_REGISTER, // ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ); - создать квар. G_CVAR_UPDATE, // ( vmCvar_t *vmCvar ); - обновить квар. G_CVAR_SET, // ( const char *var_name, const char *value ); - изменить квар. G_CVAR_VARIABLE_INTEGER_VALUE, // ( const char *var_name ); - взять численный квар. G_CVAR_VARIABLE_STRING_BUFFER, // ( const char *var_name, char *buffer, int bufsize ); - взять строковый квар. Зачем, если у вас есть JASS_GETSTRCVAR? G_ARGC, // ( void ); - кол-во слов в команде. G_ARGV, // ( int n, char *buffer, int bufferLength ); - возвращает слово из команды. G_FS_FOPEN_FILE, // ( const char *qpath, fileHandle_t *file, fsMode_t mode ); - открыть файл. G_FS_READ, // ( void *buffer, int len, fileHandle_t f ); - считать файл. G_FS_WRITE, // ( const void *buffer, int len, fileHandle_t f ); - записать в файл. G_FS_FCLOSE_FILE, // ( fileHandle_t f ); - закрыть файл. G_SEND_CONSOLE_COMMAND, // ( int exec_when, const char *cmd ); - отправить команду в консоль сервера. В качестве exec_when, как правило, вставляется константа EXEC_APPEND. G_DROP_CLIENT, // ( int clientNum, const char *reason ); - выбросить игрока. G_SEND_SERVER_COMMAND, // ( int clientNum, const char *fmt, ... ); - отправить игроку серверную команду (print - написать в консоли, cp - написать посередине). Не путать с игровыми - команды вроде say, team не прокатят! G_GET_USERINFO, // ( int num, char *buffer, int bufferSize ); - забирает информацию о игроке. G_SET_USERINFO, // ( int num, const char *buffer ); - присваивает информацию игроку. G_GET_SERVERINFO, // ( char *buffer, int bufferSize ); - забирает информацию о сервере.
Вот список основных команд. Это не всё, команд на самом деле гораздо, гораздо больше, но по большей части вам понадобятся лишь эти. Исходный файл для плагина-примера (доступен для скачивания в файловом разделе):
Code
#include "version.h" //Переменные с информацией о плагине //Различные переменные из игры: #include <jka/game/q_shared.h> #include <jka/game/g_local.h> #include <jassapi.h> //Функции, предоставляемые ДЖАЗом
pluginres_t* g_result = NULL; //Информация о плагине plugininfo_t g_plugininfo = { "Plugin_base", //Имя плагина Plugin_Base_version, //Версия "Base for plugin", //Описание Plugin_Base_Builder, //Автор "http://www.jass.ucoz.net/", //Сайт 1, //Может ли быть плагин преостановлен 1, //Может ли быть плагин загружен при помощи консольной команды 1, //Может ли быть плагин выгружен при помощи консольной команды JASS_PIFV_MAJOR, //Версия интерфейса (содержится в jassapi.h) JASS_PIFV_MINOR }; eng_syscall_t g_syscall = NULL; mod_vmMain_t g_vmMain = NULL; pluginfuncs_t* g_pluginfuncs = NULL;
//Самая первая функция, вызываемая ДЖАЗом // pinfo - указатель на структуру g_plugininfo (для ДЖАЗа) C_DLLEXPORT void JASS_Query(plugininfo_t** pinfo) { JASS_GIVE_PINFO(); }
//Вторая функция, вызываемая ДЖАЗом //Все инструкции, выполняемые плагином при запуске, описывайте здесь // engfunc - указатель на функцию syscall движка // modfunc - указатель на функцию vmMain мода // presult - указатель на переменную результата плагина // iscmd - метод загрузки: 0 = была загружена через jass.ini, 1 = была загружена командой "jass load" C_DLLEXPORT int JASS_Attach(eng_syscall_t engfunc, mod_vmMain_t modfunc, pluginres_t* presult, pluginfuncs_t* pluginfuncs, int iscmd) { JASS_SAVE_VARS();
iscmd = 0;
return 1; //return 0; - провал }
//Самая последняя функция, вызываемая ДЖАЗом //Все инструкции, выполняемые плагином при выгрузке, описывайте здесь // - iscmd метод выгрузки; 0 = была выгружена сервером при выключении или при команде "jass force_unload", 1 = была выгружена "jass unload" C_DLLEXPORT void JASS_Detach(int iscmd) { iscmd = 0; }
//Эта функция вызывается перед вызовом функции vmMain мода (Т.е. Движок - Мод) //Все инструкции, выполняемые плагином при выключении сервера, // т.е. при cmd==GAME_SHUTDOWN, описывайте здесь C_DLLEXPORT int JASS_vmMain(int cmd, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11) {
if (cmd == GAME_CLIENT_COMMAND) { //Проверка команды (список команд содержится в g_public.h) //Для отправки команд движку используйте функцию g_syscall, //к примеру //g_syscall(G_PRINT, "Hi!\n"); //Для отправки команд моду используйте функцию g_vmMain //Список всех команд движка/мода можно узнать в файле g_public.h } else if (cmd == GAME_SERVER_COMMAND){ //JASS_RET_SUPERCEDE(1); //Команда будет заблокирована }
//Вывод команды g_syscall(G_PRINT, JASS_VARARGS("vmMain(%s)\n", JASS_MODMSGNAME(cmd)));
JASS_RET_IGNORED(1); //Команда будет пропущена }
//Эта функция вызывается перед вызовом функции syscall движка (Т.е. Мод - Движок) C_DLLEXPORT int JASS_syscall(int cmd, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11, int arg12) { /* if (cmd == G_PRINT) { JASS_RET_SUPERCEDE(1); //блокировка вывода } */ g_syscall(G_PRINT, JASS_VARARGS("syscall(%s)\n", JASS_ENGMSGNAME(cmd)));
JASS_RET_IGNORED(1); }
//Эта функция вызывается ПОСЛЕ вызова функции vmMain мода (Т.е. Движок - Мод) //Все инструкции, выполняемые плагином при включении сервера, // т.е. при cmd==GAME_INIT, описывайте здесь C_DLLEXPORT int JASS_vmMain_Post(int cmd, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11) { g_syscall(G_PRINT, JASS_VARARGS("vmMain_Post(%s)\n", JASS_MODMSGNAME(cmd))); JASS_RET_IGNORED(1); }
//Эта функция вызывается ПОСЛЕ вызова функции syscall движка (Т.е. Мод - Движок) C_DLLEXPORT int JASS_syscall_Post(int cmd, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11, int arg12) { g_syscall(G_PRINT, JASS_VARARGS("syscall_Post(%s)\n", JASS_ENGMSGNAME(cmd))); JASS_RET_IGNORED(1); }
//Эта функция вызывается при обращению к плагину другим плагином или джазом //Здесь программист пишет функционал, который предоставляет его плагин другим C_DLLEXPORT int JASS_pluginCall(int cmd, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11, int arg12) { return 0; }
Итак, опишу подробнее, как выглядит общение между движком (jamp.exe/jampDed.exe/linuxjampded), джазом, плагинами и модом (jampgamex86.dll/jampgamei386.so).
Функции, с которыми нам придётся работать: syscall и vmMain. Движок во время работы регулярно обращается к моду, вызывая из него vmMain, и передавая через аргументы команды - как бы спрашивая: "Друг, тут такая ситуация, что делать будем?". vmMain, принимая через аргументы описание ситуации, решает, что делать. При этом довольно часто мод будет вызывать из движка функцию syscall, как бы говоря: "Так, сделай-ка это". Эти две функции можно вызывать из плагина при помощи g_syscall и g_vmMain. Ещё ньюанс - движок загружает мод лишь на время одного сеанса. То есть, при загрузке карты движок загружает мод, а затем, при смене карты или рестарте мод выгружается и загружается вновь. Только в нашем случае вместо мода грузится джаз, а уже джаз загружает мод - и плагины.
Пример работы связки движок-джаза-плагины-мод:
1) Сервер просыпается. Движок тут же загружает в память мод - вернее, думает, что загружает мод, а загружает джаз. Джаз, в свою очередь, загружает все плагины и из каждого вызывает функцию JASS_Query(), а так же загружает сам мод.
2) Мод загружен, и сервер начинает инициализацию, вызывая функцию vmMain с командой GAME_INIT. Команда, кстати, передаётся в первом аргументе функции vmMain, с g_syscall аналогично. На эту функцию реагирует джаз, вызывая из плагина функцию JASS_Attach(). Затем из этого же плагина вызывается JASS_vmMain с теми же самыми аргументами, что и для мода. То есть, при этом переменная cmd будет равна константе GAME_INIT, arg0 будет содержать levelTime, arg1 - randomSeed, arg2 - restart, а все arg3-arg12 будут нулевыми, т.к. никаких аргументов при передаче GAME_INIT моду больше не требуется. Для справки можете глянуть список команд из мода.
3) Далее, закончив с плагинами, джаз вызывает функцию vmMain из мода. Тот инициализирует всё, что захочет. Но, дело на этом не кончается - джаз, дождавшись конца инициализации, вновь вызывает из плагина функцию, но на этот раз JASS_vmMain_Post() - с теми же аргументами. На этом процесс завершается.
4) Всё-всё инициализировано, игра пошла. Здесь происходит обмен самыми разными сообщениями. Вот, к примеру, присоединился игрок. Я взял этот пример, т.к. он довольно нетиповой. Движок вызывает джаз с командой GAME_CLIENT_CONNECT. Джаз, подумав маленько, вызывает JASS_vmMain() с командой GAME_CLIENT_CONNECT, аргументами arg0=clientNum, arg1=firstTime, arg2=isBot. clientNum - идентификатор клиента 0-31 (всё-всё связанное с игроками происходит через идентификатор клиента). firstTime означает, что игрок только-только присоединился к серверу. Обратите внимание, что при смене карты джаз, мод и плагины выгружаются ии загружаются заново, а игравшие в это время игроки фактически выходят и переприсоединяются к серверу. Именно для того, чтобы отличить, пришёл ли игрок в первый раз, или он уже находился на сервере до рестарта, и введена эта переменная - во втором случае у этих игроков аргумент firstTime будет равен 1. Ну а isBot означает, что игрок - бот. И снова, джаз вызывает vmMain() из мода, а затем JASS_vmMain_Post() из плагина. Кстати, если вы хотите что-то сделать с клиентом, лучше это делать в функции JASS_vmMain_Post(). Ещё одно "но" - если вы блокируете команды вызовом JASS_RET_SUPERCEDE(), то обычно в скобках указывается 1, но в случае GAME_CLIENT_CONNECT там должен быть указатель на строку с причиной, почему игроку не позволено зайти на сервер. Вообще, выход из функции осуществляется при помощи макросов JASS_RET*, которые описаны в jassapi.h: JASS_RET_IGNORED(x) - оригинальная функция из мода будет вызвана, её результат будет передан движку. JASS_RET_OVERRIDE(x) - оригинальная функция из мода будет вызвана, но ее результат будет подменён. JASS_RET_SUPERCEDE(x) - оригинальная функция не будет вызвана и будет возвращен данный результат JASS_RET_ERROR(x) - JASS выдает сообщение с ошибкой и именем сообщения движка/мода JASS_SET_RESULT(x) - выход с подменой результата. Аналогична JASS_RET_OVERRIDE, но для _Post функций.
5) Игрок присоединился, зашёл в игру (GAME_CLIENT_BEGIN), и вызвал какую-то команду. Движок вызывает команду GAME_CLIENT_COMMAND, джаз передаёт её нам в плагин... Ну, вы уже поняли, вызывается JASS_vmMain с cmd=GAME_CLIENT_COMMAND, arg0=clientNum... Стоп, а сама команда где? Всё просто. Движок уже разбил команду на слова - как мило с его стороны. Делаем так: int argc = g_syscall(G_ARGC); С помощью g_syscall мы вызвали функцию syscall с командой G_ARGC из движка. ARGC= arguments count. Проще говоря, мы спросили у движка, сколько аргументов в команде. Кстати, так же при помощи g_syscall(G_PRINT, "Message\n") мы напишем сообщение "Message" в консоль сервера. Теперь в переменной argc содержится количество аргументов в команде. Дальше вызываем g_syscall(G_ARGV, 0, command, sizeof(command)); По этой команде мы получаем нулевой аргумент команды - то есть, саму команду. Затем, в цикле 1:argc мы можем брать аргументы команды. Пример - мы решили писать в логи про голосования игроков.
Code
//Кроссплатформенная функция сравнения #define strcasecmp stricmp int argc = g_syscall(G_ARGC);//кол-во аргументов взяли g_syscall(G_ARGV, 0, command, sizeof(command));//команду взяли if (!strcasecmp(command,"callvote")){//Если наша команда - голосование int i = 0; char tmparg[1024]; JASS_WRITEJASSLOG(command);//Запись в логи джаза команды JASS_WRITEGAMELOG(command);//Запись в логи игры комадны for (i=1; i<argc; ++i){ g_syscall(G_ARGV, i, tmparg, sizeof(tmparg));//Взяли аргумент под номером i JASS_WRITEJASSLOG (JASS_VARARGS(" %s",tmparg));//Запись в логи джаза аргумента JASS_WRITEGAMELOG (JASS_VARARGS(" %s",tmparg));//Запись в логи игры аргумента } //Ну и напоследок - нельзя забывать про перенос строки в конце JASS_WRITEJASSLOG("\n"); JASS_WRITEGAMELOG("\n"); }
Кстати, чуть не забыл - если вы создали собственную команду, и в команде указывается номер другого игрока - к примеру, сообщить этому игроку что-то, то не забудьте проверять, что номер этого другого игрока принадлежит диапазону от 0 до sv_maxclients - "хакеры" не дремлют.
6) А теперь представим, что сам мод вызывает функцию syscall() из движка (напомню, плагины вызывают эту же функцию при помощи g_syscall(), и этот вызов другими плагинами не перехватится). Допустим, мод собирается что-то напечатать и вызывает syscall с командой G_PRINT. При этом джаз сначала вызовет JASS_syscall из плагина - командой будет G_PRINT, arg0=string. Его обработка примерно аналогична обработке в JASS_vmMain.
7) Ну, с самыми типовыми задачами разобрались, игрок вышел (GAME_CLIENT_DISCONNECT - не буду процесс описывать), пора и сервер вырубать. При этом вызывается функция плагина JASS_vmMain с командой GAME_SHUTDOWN и без аргументов, а потом GAME_SHUTDOWN передаётся моду, потом вызывается JASS_vmMain_Post(). Затем, джаз начинает выгрузку всех плагинов, вызывая при этом из них JASS_Detach(), и выгружает мод. А затем движок выгружает сам джаз.
8) А теперь про то, за что отвечает JASS_pluginCall. Эта функция не создана для ЖА, она создана для того, чтобы к вашему плагину могли обращаться другие. Если вы не собираетесь предоставлять интерфейс другим плагинам, не трогайте эту функцию. Однако, создание данной функции является правилом хорошего тона. В противном случае - создайте отдельный заголовочный файл с командами. К примеру, интерфейс для стандартного плагина AntiDDoS выглядит так:
Code
/********************************/ /* Inteface for AntiDDoS plugin */ /********************************/
Как видите, интерфейс схож с командами vmMain или syscall. Для вызова JASS_pluginCall из другого плагина следует использовать JASS_PLUGINCALL (ID,...).К примеру, как Protection банит через AntiDDoS:
Code
int adID=JASS_GETPLUGINID("AntiDDoS"); bool banned=false; if(adID!=-1){ banned = JASS_PLUGINCALL(adID,AD_BAN,(int)(char*)ip,300000); if(banned){ PrintNLog(JASS_VARARGS("AntiFake: Client %d:\"%s\" was banned for 5 mins, ip: %s\n",arg0,getname(arg0),ip)); } }
А вот как выглядит интерфейс в самом антиддосе:
Code
C_DLLEXPORT int JASS_pluginCall(int cmd, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11, int arg12) { if(cmd==AD_BAN){ //BOOL (char *szIP, size_t ltime); return AddBan((char *)arg0, arg1); }else if(cmd==AD_UNBAN){ //void (char *szIP); if(!strcasecmp((char *)arg0,"all")){ UnbanAll(); }else{ Unban((char *)arg0); } }else if(cmd==AD_BANLIST){ //char *(int num, int count); return (int)ListBan(arg0,arg1); }
return 0; }
9. Отладка. Сделали плагинчик, пора и тестировать. Ага, падает сервак? 100% гарантия, что без этого не обойдётся. Объясню, как плагины дебажить. Предполагается, что у вас есть MS Visual Studio. Отладка под Windows: 1) Открываете настройки проекта (у меня MSVC на английском, вводить все значения без кавычек). 2) Раздел Debugging: 2.1) Command - вводите полный путь до exe-шника. Пример: "D:\Games\Jedi Academy\GameData\jampDed.exe" 2.2) Command arguments - вводите аргументы для запуска. К примеру, "+set net_port 29070 +set dedicated 2 +exec server.cfg +set fs_game JASS_Release" 2.3) Working Directory - путь до папки GameData. К примеру, "D:\Games\Jedi Academy\GameData" 3) Раздел Linker: 3.1) Output file - полный путь до файла плагина, по которому выкладывать скомпилированную dll-ку. К примеру, "D:\Games\Jedi Academy\GameData\JASS_Release\Plugins\$(ProjectName).dll". Путь достаточно сменить лишь для Debug - режима. 4) Нажимаете F5, и начинаете отладку. Отладка под Linux: 1) Отлаживайте. 2) лучше. 3) под. 4) Windows. 5) 95% ошибок общие для обеих платформ, обычно я только делаю стабильную версию для Windows, портирую и получаю стабильную версию под Linux. Если же ошибка появляется только на Linux, используйте gdb, с гуёвыми дебаггерами лучше не связываться. Ибо эти дебагерры гуёвые совсем не только от слова GUI.
Надеюсь, суть вы уловили. Если возникнут вопросы - не стесняйтесь
Считывание команды игрока или админа (через ркон):
Code
if (cmd == GAME_CLIENT_COMMAND/*GAME_SERVER_COMMAND для серверной консоли*/) { int argc = g_syscall(G_ARGC); g_syscall(G_ARGV, 0, command, sizeof(command)); if (!strcasecmp(command,"cmd")){ char tmparg[1024]; for (int i=1; i<argc; ++i){ //args } } }
Печать в чат:
Code
int sv_maxclients = JASS_GETINTCVAR("sv_maxclients"); for(int i=0;i<sv_maxclients;++i){ char *chat = JASS_VARARGS("chat \"%s\n\"", "What_you_want_to_print"); g_syscall(G_SEND_SERVER_COMMAND, i, chat ); }
Для того, чтобы отправить команду всем игрокам, можно вместо номера игрока указывать -1, но тогда почему-то печатается сообщение в верхнем левом углу. Так что - цикл.
Кстати, в arg0 для большинства команд передаётся номер инициировавшего её игрока.
Взятие параметра из информации об игроке и присваивание параметра из строки информации об игроке. Строка берётся с помощью G_GET_USERINFO и присваивается G_SET_USERINFO.
Code
char *Info_ValueForKey( const char *s, const char *key ) { char pkey[BIG_INFO_KEY]; static char value[2][BIG_INFO_VALUE]; // use two buffers so compares // work without stomping on each other static int valueindex = 0; char *o;
if ( !s || !key ) { return ""; }
if ( strlen( s ) >= BIG_INFO_STRING ) { g_syscall( G_PRINT, "Info_ValueForKey: oversize infostring" ); return ""; }
valueindex ^= 1; if (*s == '\\') s++; while (1) { o = pkey; while (*s != '\\') { if (!*s) return ""; *o++ = *s++; } *o = 0; s++;
o = value[valueindex];
while (*s != '\\' && *s) { *o++ = *s++; } *o = 0;
if (!strcmp(key, pkey) ) return value[valueindex];
if ( strlen( s ) >= MAX_INFO_STRING ) { g_syscall( G_PRINT, "Info_RemoveKey: oversize infostring"); }
if (strchr (key, '\\')) { return; }
while (1) { start = s; if (*s == '\\') s++; o = pkey; while (*s != '\\') { if (!*s) return; *o++ = *s++; } *o = 0; s++;
o = value; while (*s != '\\' && *s) { if (!*s) return; *o++ = *s++; } *o = 0;
if (!strcmp (key, pkey) ) { strcpy (start, s); // remove this part return; }
if (!*s) return; }
}
Взятие имени мода. Используйте эту функцию вместо прямого взятия имени из fs_game
Code
char base []="base"; const char * gamedir () { const char * game = JASS_GETSTRCVAR("fs_game"); if (!game[0]) return base; return game; }
Проверка, является ли игрок ботом. Это нужно, так как бот приходят на сервер "неявно", минуя вызов GAME_CLIENT_CONNECT (эта команда вызывается только при перезаходе бота при смене карты). Для работы требуется взять список энтити (см выше).
Code
bool is_bot = g_gents[arg0].r.svFlags&SVF_BOT;
Получаем указатель на структуру level (в level хранятся всякие вкусности, как строки с голосованием ).
Code
if (cmd == G_FS_FOPEN_FILE) { if (arg2 == FS_APPEND || arg2== FS_APPEND_SYNC) { if (!strcasecmp(JASS_GETSTRCVAR("g_log"), (char*)(arg0))) { //level_locals_t *g_level = NULL; g_level=(level_locals_t*)(arg1-20); //arg is a pointer to level.logFile :D, 20 is offset } } }
Увы, этот метод работает только когда логи включены. Кстати, открою секрет - на патче 1.0.1 для базы на винде указатель на level всегда 0x207EEA60, а для линукса - точка входа библиотеки+0x0068A3A0. Как взять точку входа - смотрите в исходниках academy5.
int sv_maxclients = JASS_GETINTCVAR("sv_maxclients"); for(int i=0;i<maxclients;++i){ g_syscall(G_SEND_SERVER_COMMAND, i, JASS_VARARGS("chat \"%s\n\"", "What_you_want_to_print"); } Для того, чтобы отправить команду всем игрокам, можно вместо номера игрока указывать -1, но тогда почему-то печатается сообщение в верхнем левом углу. Так что - цикл.
Hepo, ага, особенность движка ЖА. Не знал об этом - я всегда делал if (cmd== GAME_CLIENT_CONNECT && !arg2), отсеивая ботов, и никогда не замечал что их и так не ловит О_о
вы спросите - что такое конфигстринг и откуда взялось 1311? конфигстринги - это особые данные, которые передаются от сервера к клиентам и хранят в себе некоторые важные настройки. Конкретно: 0 - информация о сервере 1 - еще одна информация о сервере (другая) 2 - музыка на карте 3 - название карты (пишется 4-той строкой при загрузке карты) 1131 -> 1163 обрезанные userinfo игроков
в jka 1700 этих конфигстрингов. Учтите, что ВСЕ именения будут приняты ТУТ ЖЕ. экспериментируйте
Message edited by Hepo - Friday, 28.12.2012, 12:19