PDA

Просмотр полной версии : [CMD] /bug и /sug



Osetin
02.01.2014, 18:05
#define BUG_REPORT_FILE_NAME "BugLog.txt"
#define SUGGESTION_FILE_NAME "SugLog.txt"
#define BUG_REPORT_COOLDOWN_TIME 60

bool:CheckBugReportCooldown(playerid)
{
static bug_report_tick[MAX_PLAYERS];
new current_tick = tickcount();
static const cooldown_message[] =
!"Отчитываться о багах и писать предложения можно раз в "\
#BUG_REPORT_COOLDOWN_TIME" секунд.";
if (current_tick < bug_report_tick[playerid] + BUG_REPORT_COOLDOWN_TIME * 1000)
return bool:SendClientMessage(playerid, -1, cooldown_message);
bug_report_tick[playerid] = current_tick;
return false;
}

CMD:bug(playerid, params[])
{
if (CheckBugReportCooldown(playerid))
return 1;
if (sscanf(params, "s[129]", params))
return SendClientMessage(playerid, -1, !"Использование: /bug [описание бага]");
static const bug_str[] = " сообщил о баге: ";
new string[sizeof(bug_str)+MAX_PLAYER_NAME+128];
GetPlayerName(playerid, string, sizeof(string));
strcat(string, bug_str), strcat(string, params);
new File:f = fopen(!BUG_REPORT_FILE_NAME, io_append);
if (f == File:0)
return SendClientMessage(playerid, -1,
!"Ошибка: Не удалось открыть файл \"" BUG_REPORT_FILE_NAME "\" !");
for (new i = -1; string[++i] != '\0';)
fputchar(f, string[i], false);
fputchar(f, '\n', false);
fclose(f);
SendClientMessage(playerid, -1, !"Вы успешно сообщили о баге. Спасибо!");
string[0] = ' ', string[1] = '\0', strcat(string, params);
return SendClientMessage(playerid, -1, string);
}

CMD:sug(playerid, params[])
{
if (CheckBugReportCooldown(playerid))
return 1;
if (sscanf(params, "s[129]", params))
return SendClientMessage(playerid, -1, !"Использование: /sug [предложение по улучшению]");
static const sug_str[] = " предложил: ";
new string[sizeof(sug_str)+MAX_PLAYER_NAME+128];
GetPlayerName(playerid, string, sizeof(string));
strcat(string, sug_str), strcat(string, params);
new File:f = fopen(!SUGGESTION_FILE_NAME, io_append);
if (f == File:0)
return SendClientMessage(playerid, -1,
!"Ошибка: Не удалось открыть файл \"" SUGGESTION_FILE_NAME "\" !");
for (new i = -1; string[++i] != '\0';)
fputchar(f, string[i], false);
fputchar(f, '\n', false);
fclose(f);
SendClientMessage(playerid, -1, !"Вы успешно написали предложение по улучшению. Спасибо!");
string[0] = ' ', string[1] = '\0', strcat(string, params);
return SendClientMessage(playerid, -1, string);
}


Например, игрок пишет: /bug замечен баг на работе грузчика. А команда /sug для предложения по улучшению сервера.

TWIX
02.01.2014, 20:44
Неплохо но можно проще на sscanf )!

L0ndl3m
02.01.2014, 20:57
Неплохо но можно проще на sscanf )!

А разве команды не на sscanf? :acute:

Daniel_Cortez
02.01.2014, 21:46
Неплохо но можно проще на sscanf )!

А разве команды не на sscanf? :acute:
Проще будет наоборот без sscanf: в аргументе params и так уже есть строка с введёнными данными. Достаточно лишь использовать isnull для проверки на пустую строку.

P.S.: Мне кажется, или сообщения записываются через sscanf не в строку, а в числовую переменную? Чревато выходом за пределы буфера.


UPD: Переписал обе команды. Исправил баг с потерей вводимых данных.
Первый пост обновлён.

Daniel_Cortez
26.05.2015, 18:40
Ещё раз переписал команды. Устранил уязвимость, с помощью которой можно было флудом команд остановить работу сервера из-за операций с файлами.

Mazzilla
28.05.2015, 06:30
Ещё раз переписал команды. Устранил уязвимость, с помощью которой можно было флудом команд остановить работу сервера из-за операций с файлами.
Для чего используется отрицание ('!') перед текстом? Не понял что-то.

И зачем в конце команды выполнять такие действия, когда можно вернуть истину?)

string[0] = ' ', string[1] = '\0', strcat(string, params);
return SendClientMessage(playerid, -1, string);

Daniel_Cortez
28.05.2015, 12:42
Для чего используется отрицание ('!') перед текстом? Не понял что-то.



И зачем в конце команды выполнять такие действия, когда можно вернуть истину?)
В командах можно вообще не возвращать никаких значений - в этом случае компилятор автоматически подставит в конце функции инструкции, соответствующие return 1 (const.pri1 \ retn).
Я же сделал возврат результата SCM, поскольку эта функция в любом случае вернёт 1 (игрок, вызвавший команду, всегда подключен).
А раз функция всегда возвращает 1, почему бы не воспользоваться этим значением? Это чуть ли не самая распространённая оптимизация среди скриптеров.

1lyad
15.09.2016, 17:59
new string[sizeof(sug_str)+MAX_PLAYER_NAME+144];
new string[sizeof(bug_str)+MAX_PLAYER_NAME+144];
Почему 144, если максимальное вводимое количество символов = 128, а если еще учесть "/sug_" / "/bug_", значит 128-5 = 123.
Если ошибаюсь, поправьте.

DeimoS
16.09.2016, 09:26
new string[sizeof(sug_str)+MAX_PLAYER_NAME+144];
new string[sizeof(bug_str)+MAX_PLAYER_NAME+144];
Почему 144, если максимальное вводимое количество символов = 128, а если еще учесть "/sug_" / "/bug_", значит 128-5 = 123.
Если ошибаюсь, поправьте.

128 символов можно ввести в окно чата
144 можно отобразить в SendClientMessage
Мы не просто выводим текст из чата, а ещё добавляем к нему свою информацию, отображая через SendClientMessage => в данном случае действует ограничение в 144 символа, а не в 128 (игрок ввёл 128 символов в чате + прикрепился ник + прикрепился ID. Уже вышло больше 128).

Непонятно только одно: к чему все эти вычисления, если SendClientMessage никак не отобразит больше 144 символов (если не использовать zmessage (http://pro-pawn.ru/showthread.php?14024-zmessage-%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE%D1%81%D1%82%D1%80%D0%BE%D1%87%D0%BD%D1%8B%D0%B5-%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D1%8F), конечно).
Логично сделать так:

new string[MAX_CHATBUBBLE_LENGTH+1];
new string[MAX_CHATBUBBLE_LENGTH+1];

1lyad
16.09.2016, 10:33
128 символов можно ввести в окно чата
О чём я и говорю, игрок может ввести максимально 128 символов, так какой смысл прибавлять к string'у 144 символа, если игроку будет выводиться только сообщение, которое он ввёл после "/bug", а значит, 124 символа, потому что пробел тоже будет выведен игроку, если заменять первый символ string на пробел.


144 можно отобразить в SendClientMessage
Мы не просто выводим текст из чата, а ещё добавляем к нему свою информацию, отображая через SendClientMessage.
Посмотри на данный код.

string[0] = ' ', string[1] = '\0', strcat(string, params);

Если да, то игроку просто выведет следующие два сообщения:

SendClientMessage(playerid, -1, !"Вы успешно сообщили о баге. Спасибо!"); // 1.
string[0] = ' ', string[1] = '\0', strcat(string, params);
return SendClientMessage(playerid, -1, string); // 2: string = params.
// Кстати, не совсем понял, почему бы просто не использовать:
// return SendClientMessage(playerid, -1, params);
// Из-за того, что пробела не будет в начале сообщения?

А теперь посмотрим где используется string на примере команды /bug:



//static const bug_str[] = " сообщил о баге: ";
new string[sizeof(bug_str)+MAX_PLAYER_NAME+144]; // new string[18 + 24 + 144]
GetPlayerName(playerid, string, sizeof(string)); // "Firstname_Lastname"
strcat(string, bug_str); // "Firstname_Lastname сообщил о баге: "
strcat(string, params); // "Firstname_Lastname сообщил о баге: введенный текст игроком, после команды /bug";
fwrite(bug_report_file, string); // записали в BugLog.txt всё содержимое переменной string;
string[0] = ' ', string[1] = '\0', strcat(string, params); // " введенный текст игроком, после команды /bug";
return SendClientMessage(playerid, -1, string); // выводим игроку содержимое переменной string.
}

Теперь, собственно, вопрос, если мы уже знаем, что максимально выводимое количество символов в данном случае просто не может быть равно 144, ибо SA:MP не позволит ввести игроку столько.
И вообще, если бы даже захотели вывести игроку 144 символа, то в переменной string предостаточно ячеек, в данном случае мы используем такое количество ячеек, чтобы всё полностью записалось в BugLog.txt.

UPD:
Непонятно только одно: к чему все эти вычисления, если SendClientMessage никак не отобразит больше 144 символов (если не использовать zmessage (http://pro-pawn.ru/showthread.php?14024-zmessage-%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE%D1%81%D1%82%D1%80%D0%BE%D1%87%D0%BD%D1%8B%D0%B5-%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D1%8F), конечно).
Логично сделать так:

new string[MAX_CHATBUBBLE_LENGTH+1];
new string[MAX_CHATBUBBLE_LENGTH+1];


в данном случае мы используем такое количество ячеек, чтобы всё полностью записалось в BugLog.txt.

Damik
16.09.2016, 10:53
О чём я и говорю, игрок может ввести максимально 128 символов, так какой смысл прибавлять к string'у 144 символа, если игроку будет выводиться только сообщение, которое он ввёл после "/bug", а значит, 124 символа, потому что пробел тоже будет выведен игроку, если заменять первый символ string на пробел.


Посмотри на данный код.

string[0] = ' ', string[1] = '\0', strcat(string, params);

Если да, то игроку просто выведет следующие два сообщения:

SendClientMessage(playerid, -1, !"Вы успешно сообщили о баге. Спасибо!"); // 1.
string[0] = ' ', string[1] = '\0', strcat(string, params);
return SendClientMessage(playerid, -1, string); // 2: string = params.
// Кстати, не совсем понял, почему бы просто не использовать:
// return SendClientMessage(playerid, -1, params);
// Из-за того, что пробела не будет в начале сообщения?

А теперь посмотрим где используется string на примере команды /bug:


Теперь, собственно, вопрос, если мы уже знаем, что максимально выводимое количество символов в данном случае просто не может быть равно 144, ибо SA:MP не позволит ввести игроку столько.
И вообще, если бы даже захотели вывести игроку 144 символа, то в переменной string предостаточно ячеек, в данном случае мы используем такое количество ячеек, чтобы всё полностью записалось в BugLog.txt.

UPD:

:scratch_one-s_head:

DeimoS
16.09.2016, 12:23
...

Если честно, я особо не смотрел до этого код и думал, что сообщение о баге выводится админам :blush:
Ты во всём прав

Boulevard_Picard
24.07.2018, 03:30
Русский текст сохраняется в виде кракозябр

Boulevard_Picard[PC] ñîîáùèë î áàãå: 11111111111

Daniel_Cortez
24.07.2018, 13:28
Русский текст сохраняется в виде кракозябр

Boulevard_Picard[PC] ñîîáùèë î áàãå: 11111111111
Да, действительно, fwrite() (http://wiki.pro-pawn.ru/wiki/Fwrite) пытается сохранить неупакованную строку в UTF-8, а если её упаковать - запишутся случайные мусорные данные. Единственный способ правильно записать символы кириллицы - выполнять запись по одному символу с помощью fputchar() (http://wiki.pro-pawn.ru/wiki/Fputchar), что я и сделал в новой реализации.

1-й пост обновлён.