Обработка команд в OnPlayerCommandText. -
Maccer - 29.11.2010
Хочу поделиться с вами одним из способов обработки команд, введенных игроком (OnPlayerCommandText).
Так как в программировании важна декомпозиция, то логично было бы описывать обработку различных команд в разных файлах исходного кода (команды /buyhouse /setrent в файле описывающем систему домов, команды /ban /kick в отдельном файле с админскими командами и тд), и сейчас я покажу один из способов это реализовать.
Для начала создаем файл command.inc, в нем у нас будет описан паблик OnPlayerCommandText.
Идея заключается в том, чтобы для каждой команды создать свою функцию, а в OnPlayerCommandText определять какая функция соответствует введенной команде и вызывать ее, передав ей массив введенных параметров.
С начала напишем саму функцию, которая будет превращать строку в двумерный массив параметров, первым из которых (под номером 0) будет название самой функции, зачем увидите дальше. Вот собственно ее код:
pawn Code:
cmdtext2params(const cmdtext[], params[][], size1 = sizeof params, size2 = sizeof params[])
{
new currentparam;
new n;
new c = 1; // пропускаем слэш
while(cmdtext[c])
{
if(cmdtext[c] != ' ') {
if(currentparam >= size1) break;
if(n < size2-1) params[currentparam][n++] = cmdtext[c];
}
else if(cmdtext[c+1] && cmdtext[c+1] != ' ') {
currentparam++;
n=0;
}
c++;
}
#if defined DEBUG
for(n=0;n<min(currentparam+1,size1);n++)
printf("cmd param %d: %s", n, params[n]);
#endif
}
Теперь нам потребуется написать несколько макросов, облегчающих добавление новой команды.
pawn Code:
#define cmd(%1) if(strcmp(#%1,params[0],true)==0){cmd_%1(playerid);return(1);}
#define cmdf(%1) if(strcmp(#%1,params[0],true)==0){cmdf_%1(playerid,params);return(1);}
#define altername(%1,%2) if(strcmp(#%2,params[0],true)==0){cmd_%1(playerid);return(1);}
#define alternamef(%1,%2) if(strcmp(#%2,params[0],true)==0){cmdf_%1(playerid,params);return(1);}
Первый макрос создан для команд без параметров, второй для команд с параметрами, третий и четвертый позволяют задавать альтернативные имена для команд.
В конце файла на всякий случай убираем макросы.
pawn Code:
#undef cmd
#undef cmdf
#undef altername
#undef alternamef
Теперь наконец опишем саму функцию OnPlayerCommandText
pawn Code:
public OnPlayerCommandText(playerid, cmdtext[])
{
new params[7][20]; // массив параметров
cmdtext2params(cmdtext, params); // выдираем параметры из строки
if(!params[0][0]) return 0; // если нулевой параметр(имя команды) не заданно, то делать нам тут нечего - возвращаем ноль
// теперь собственно список самих команд:
cmd(kill)
altername(kill,умри) // задаем альтернативное имя для команды kill
cmdf(givemoney)
alternamef(givemoney,gm)
return 0;
}
В ней перечислены две команды - одна с параметрами, другая без. И альтернативные имена для каждой из них.
Наш макрос преобразует каждую из этих строчек в сравнение значения в скобках с введенной командой из params[0] и в случае совпадения вызовет функцию с именем cmdf_имякоманды и параметрами playerid и params. Обратите внимание, что в местах использования макроса мы не ставим точку с запятой, а между параметрами altername не ставим лишних пробелов. Создать русскоязычную команду можно только через altername/alternamef.
Теперь в отдельном файле опишем функции соответствующие нашим командам.
pawn Code:
cmd_kill(playerid)
{
SetPlayerHealth(playerid, 0);
}
cmdf_givemoney(playerid, params[][])
{
if(!IsPlayerAdmin(playerid))
{
SendClientMessage(playerid, COLOR_RED, "У вас нет прав на использование этой команды.");
return 1;
}
if(!params[1][0] || !params[2][0])
{ // удобная проверка на все необходимые параметры в одном месте.
new string[MAX_STRING];
/* за счет передачи имени введенной команды в params[0] - хелп будет универсален для различных имен команды */
format(string, sizeof string, "ИСПОЛЬЗОВАНИЕ: /%s [playerid] [money]", params[0]);
SendClientMessage(playerid, COLOR_HELP, string);
return 1;
}
new player = strval(params[1]);
if(!IsPlayerConnected(player))
{
SendClientMessage(playerid, COLOR_RED, "Нет такого игрока.");
return 1;
}
new money = strval(params[2]);
GivePlayerMoney(player, money);
return 1;
}
Так как параметры уже разделены, мы можем легко проверить какой из них задан а какой нет (params[][0] не равен нулю).
А так как у нас для одной функции существует несколько имен и чтобы для /gm не выдавался хелп с описанием /givemoney мы форматируем строчку используя введенную игроком команду (передается в params[0]).
В функцию cmd_kill никаких параметров не передается, так как они там не нужны.
command.inc -
http://pastebin.com/7c8Y9FJY
new.pwn -
http://pastebin.com/STsZMusG
Re: Обработка команд в OnPlayerCommandText. -
Aleks10 - 30.11.2010
это конечно, не самое быстрое, но зато лёгкое и красивое
автору ++ !
п.с. забыл в функцие cmdtext2params указывать границу кол-ва параметров и длины строки
если выйти за пределы функция рухнет
Re: Обработка команд в OnPlayerCommandText. -
Kernell - 30.11.2010
Баян.
https://sampwiki.blast.hk/wiki/Dcmd
Re: Обработка команд в OnPlayerCommandText. -
Maccer - 30.11.2010
Quote:
Originally Posted by Aleks10
п.с. забыл в функцие cmdtext2params указывать границу кол-ва параметров и длины строки
если выйти за пределы функция рухнет
|
Верное замечание, я уже не помню, когда писал функцию либо не подумал, либо осознанно этот момент упустил. В общем исправил - теперь должно быть норм.
Главное не забудьте изменить размерность массива new params[7][20]; под свои нужды, у кого-то могут быть команды с более чем 7 параметрами или длинной параметра более 20 символов.
Quote:
Originally Posted by Kernell
|
Мой метод есть продолжение идеи dcmd, но я старался сделать добавление команд наиболее простым, там надо писать dcmd(heal, 4, cmdtext); а у меня просто cmdf(heal) что я думаю удобней, так как считать кол-во символов каждый раз не лучшая идея.
Последней каплей был
этот пост. И я решил поделиться с людьми своим виденьем того, как надо обрабатывать команды. ))
Есть еще подобная
тема у Y_Less, но там она имхо слишком навороченная.
Re: Обработка команд в OnPlayerCommandText. -
Aleks10 - 01.12.2010
да, от yless слишком навороченная...
в данной теме написан самый минимум(ну разве что, можно было бы добавить для каждой команды help?

)
Re: Обработка команд в OnPlayerCommandText. -
OKStyle - 23.12.2010
Вот если сделаешь поддержку кириллицы вида cmd_купить, тогда и посмотрим...
Re: Обработка команд в OnPlayerCommandText. -
Maccer - 28.12.2010
Quote:
Originally Posted by OKStyle
Вот если сделаешь поддержку кириллицы вида cmd_купить, тогда и посмотрим...
|
Не думал что кому-то может понадобится кириллица в командах.
В общем можно сделать, если создать команду cmdf_buy, а потом уже по старинке
pawn Code:
if(strcmp("купить",params[0],true)==0){cmdf_buy(playerid,params);return(1);}
Re: Обработка команд в OnPlayerCommandText. -
OKStyle - 28.12.2010
Пфф.. а не проще тогда уж define'ом?
Re: Обработка команд в OnPlayerCommandText. -
Romanius - 29.12.2010
у меня была идея как сделать поддежку кирилицы. но она не будет работать достаточно быстро если ее написанть на PAWN
Re: Обработка команд в OnPlayerCommandText. -
Maccer - 11.01.2011
Добавил в туториал описание макросов для создания альтернативных (в том числе русскоязычных) команд.