PDA

Просмотр полной версии : [Вопрос] DC_CMD



Vano_Glad
09.02.2016, 08:00
Такой вопрос. Тема касается не только этого командного процессора. Допустим есть проверка на все веденные аргументы в команде:


if(sscanf(params,"is[128]", params[0], params[1])) return
SCM(playerid, COLOR_WHITE, "Введите: /kick [id] [причина]);

И делаем следующее:


static const fmt_str[] = "Администратор %s кикнул игрока %s. Причина: %s";
new string[sizeof(fmt_str)-2+MAX_PLAYER_NAME-2+MAX_PLAYER_NAME-2+128];

Как видно +128 и s[128]

Нужно ли подсчитывать в string 128 ячеек для вывода текста, если в проверке я уже выставил длину? Или может я что-то не так понимаю, или может хитрость какая-то есть?

Desulaid
09.02.2016, 08:09
Массив ваш равен 217, когда лимит вам для SendClientMessage дан на 144 символа. Можно же в голове представить формулу 144 = x - (sizeof(fmt_str)-2*3+MAX_PLAYER_NAME*2). Алгебра 5 класс :)


static const fmt_str[] = "Администратор %s кикнул игрока %s. Причина: %s";
new string[144-(sizeof(fmt_str)-2*3+MAX_PLAYER_NAME*2)];

А если залогируете размер, то узнаете размер для параметра


printf("%i", sizeof(string));

ADD: а массив string надо тогда делать в 144 символа, причину, наверно, вы знаете.

Vano_Glad
09.02.2016, 08:57
Конкретного ответа я так и не получил. Видимо вы меня не правильно поняли. Я понял всю эту тему так: В s[128] - максимальная длина текста, которую я могу ввести, а в string длина должна быть не более 128 символов, следовательно я для s[128] вместо 128 должен подобрать такое число, чтобы оно уходило в остаток - верно?

Daniel_Cortez
09.02.2016, 09:11
http://wiki.sa-mp.com/wiki/SendClientMessage

If a message is longer than 144 characters, it will not be sent. Truncation can be used to prevent this. Displaying a message on multiple lines will also solve this issue.

Btw, на строковый буфер следует выделять не 144, а 145 ячеек - надеюсь, не нужно напоминать, почему.

Vano_Glad
09.02.2016, 09:20
Конкретного ответа я так и не получил. Видимо вы меня не правильно поняли. Я понял всю эту тему так: В s[128] - максимальная длина текста, которую я могу ввести, а в string длина должна быть не более 128 символов, следовательно я для s[128] вместо 128 должен подобрать такое число, чтобы оно уходило в остаток - верно?

Что насчет этого? Тут я правильно мыслю?

Desulaid
09.02.2016, 10:09
Итак, еще раз, у тебя есть строка и формула, которая ни мои и ни твоя не совсем правильные. Так же, как и говорил DC, у нас есть строка в 145 символов. А теперь задачка, как вычислить x, если нам известны сумма и слагаемое?

Пусть ИКС - разница, тогда 145 = икс + форума => x = 145 - форума;

В роли "x" у нас массив. Просто не знаю еще как рассказать 9((


static const fmt_str[] = "Администратор %s кикнул игрока %s. Причина: %s";
new string[145-(sizeof(fmt_str)-2*3+((MAX_PLAYER_NAME+1)*2))];
printf("ИКС равен = %i", sizeof(string));

Вот и смотри свой остаток. А конкретный ответ - цифра? Если так, то после такого ответа ты ничего не поймешь и будешь задавать однотипные вопросы..

Daniel_Cortez
09.02.2016, 10:22
Зачем считать размер, если SCM всё равно не выведет больше 144 символов?
Нужно только узнать длину строки c причиной бана в sscanf. Я точно не помню максимальную длину строки params, но вы можете найти её опытным путём, а потом отнять 2 (1 на пробел между параметрами и ещё 1 - минимальная длина ID игрока).

Vano_Glad
09.02.2016, 10:27
Я все понял :) Спасибо всем. Тема закрыта

Desulaid
09.02.2016, 10:32
Я на это и намекал. Размер будет равен 54, а в массив string запихнуть число 145 и все.

Что-то типа


COMMAND:kick(playerid, params[])
{
new targetid, name[MAX_PLAYER_NAME+1], string[145];
if(sscanf(params, "us[52]", targetid, params))
return 0;
GetPlayerName(targetid, name, sizeof(name));
GetPlayerName(playerid, string, sizeof(name));
format(string, sizeof(string), "Администратор %s кикнул игрока %s. Причина: %s", string, name, params);
SendClientMessageToAll(-1, string);
Kick(targetid);
return 1;
}

Daniel_Cortez
09.02.2016, 10:48
Я на это и намекал. Размер будет равен 54, а в массив string запихнуть число 145 и все.

Что-то типа


COMMAND:kick(playerid, params[])
{
new targetid, name[MAX_PLAYER_NAME+1], string[145];
if(sscanf(params, "us[52]", targetid, params))
return 0;
GetPlayerName(targetid, name, sizeof(name));
GetPlayerName(playerid, string, sizeof(name));
format(string, sizeof(string), "Администратор %s кикнул игрока %s. Причина: %s", string, name, params);
SendClientMessageToAll(-1, string);
Kick(targetid);
return 1;
}
В причине бана игрок может ввести больше 52 символов - словишь варнинг от sscanf.

Desulaid
09.02.2016, 10:50
В причине бана игрок может ввести больше 52 символов - словишь варнинг от sscanf.


if (strlen(params) > 52)
return 0;
:grin:

Daniel_Cortez
09.02.2016, 11:26
if (strlen(params) > 52)
return 0;
:grin:
Ты смотри, а то ещё ТС не поймёт шутки и точно так же сделает.
Что касается причины бана, макс. длина params - 128 символов (вспомнил бы раньше, если бы не писал всё это параллельно с решением задач по бух. учёту на парах), следовательно в sscanf следует указывать для строки с причиной 128-1-1+1 = 127 ячеек (-1 на мин. длину числа, -1 на пробел и +1 на нуль-символ).

Vano_Glad
09.02.2016, 12:30
Ты смотри, а то ещё ТС не поймёт шутки и точно так же сделает.

Я не нуб в pawn. Так точно не сделаю. Я так понимаю в sscanf нужно всегда прописывать 127? Раз ты говоришь, что словить warning можно. То есть получается следующим образом: Независимо от того, что SendClientMessage ограниченно 144 символами, если в sscanf допустим ввести 50 символов (Типо предела (типо не хватает 50 до 144 символов)), а в игре причину ввести больше 50-ти символов, то вылетит warning?

$continue$
09.02.2016, 12:55
Если Вы выйдете за 127 символов, Вам плагин, просто отрежет строку.

http://i.imgur.com/d2nJiWm.png

DC: Кстати, в чем был профит юзать goto и бесконечный цикл?

Vano_Glad
09.02.2016, 12:59
Если Вы выйдете за 127 символов, Вам плагин, просто отрежет строку.

Конкретный ответ на мой вопрос можно получить?

$continue$
09.02.2016, 13:07
Конкретный ответ на мой вопрос можно получить?

Эм?


const MAX_SIZE_PARAMS = 127;



if(strlen(reason_bans) > MAX_SIZE_PARAMS)
return SendClientMessage(playerid, -1, "Вы привысили порог допустимых сиволов (Причина бана должна быть <= 127 символов)");

Vano_Glad
09.02.2016, 13:12
Это не совсем то что я хотел услышать :) Да и вообще, с чего пошли разговоре о бане? :D Речь шла о кике игрока с сервера. Мне всегда писать в sscanf длину 127, независимо от того, сколько символов останется в SendClientMessage или же записывать нужно именно остаток?

$continue$
09.02.2016, 13:41
Окей.
1) MAX_CHATBUBBLE_LENGTH (144) + 1 - MAX_SIZE_PARAMS(127) = 18.
2) Идем дальше, у нас остается 18, но у нас ещё 2 выхлопа на ники.
3) То есть: (MAX_PLAYER_NAME + 1 + MAX_PLAYER_NAME + 1)
4) Получается так: на 2 ника нам нужно зарезервировать 50 ячеек в памяти.
5) 50 - 18 = 32
6) MAX_CHATBUBBLE_LENGTH (144) + 1 - MAX_SIZE_PARAMS(127) + 32 (Плохая практика, конечно, программирования -_-. Magic number -_-)
7) Ну и я ещё не учел спецификаторы (думаю, доработаешь)
В итоге получаем расчет по формуле:


new fmt_str[(MAX_CHATBUBBLE_LENGTH + 1 - MAX_SIZE_PARAMS + 7) * 2 + 1)];

Daniel_Cortez
09.02.2016, 18:02
Я так понимаю в sscanf нужно всегда прописывать 127?
Зависит от того, какие ещё будут параметры, кроме строки с причиной бана. Читайте мой пост выше, там расписана формула.



DC: Кстати, в чем был профит юзать goto и бесконечный цикл?
Он не бесконечный и с помощью goto обходится присваивание нуля в cmd_end. Если честно, уже не помню, почему я сделал именно так, а не присвоил переменной cmd_end значение 0 в ветке "else if(cmdtext[pos] == ' ')", скорее всего, это осталось от старого кода отделения параметров от команды. Впрочем, это исходники от старой версии DC_CMD, в 2.6 этот код был пересмотрен ещё раз и таких извращений с goto там нет.