И вновь я Вас категорически приветствую!
(что-то нечасто это бывает...)
Ни для кого не секрет
(а может для кого-то и секрет), что в SA-MP есть баг, при котором сервер крашило если в функции SendClientMessage и SendClientMessageToAll попадает спецификатор, который не подвергся форматированию.
Когда-то с помощью этого бага появилась возможность класть сервера просто вводя в чат сообщение, в котором содержится любой спецификатор. Куй, естественно, реагировал на это со скоростью черепахи и смекалистые умельцы сделали защиту со стороны сервера путём замены всех "%" на "#".
Когда Куй наконец решил обратить на нас, обычных смертных, внимание, он добавил "защиту" со стороны клиента, просто вставив идентичный код в обработчик текста, введённого игроком в чат, а не сделав защиту напрямую в SendClientMessage, поэтому и по сей день в SA-MP можно положить любой сервер, где данные, введённые Вами в диалоговое окно, выводятся в чат через SendClientMessage
(сообщения в личку, например, или же на RP серверах сообщения на радио, если они реализованы через диалог) и не стоит подобной защиты.
Так же, если Вы сами в SendClientMessage укажете спецификатор "%s", сервер неминуемо крашнет :с
В интернете гуляют реализации, но во всех, попавшихся мне, защита реализована идентично той, что стоит в чате
(то бишь, знаки процента заменяются на знак решётки), что лично мне не совсем нравится. Поэтому я решил написать свою функцию, которая, по возможности, сможет оставить все знаки процента в сообщении игрока, при этом не доставляя никаких проблем серверу.
И написал
Защита реализована, как я уже сказал выше, в виде функции.
Код функции без описания
PHP код:
stock FindSpecifiersInString(message[], array_size = sizeof(message))
{
new message_length = strlen(message);
for(new i; i < message_length; i++)
{
if(message[i] == '%')
{
if(message_length < array_size) strins(message, "%", i++, message_length++);
else message[i] = '#';
}
}
}
Функция имеет один обязательный параметр и один совсем "ненужный" параметр.
- message[]
- собственно, массив(!) с текстом, в котором мы будем обрабатывать символы
-[/INDENT][/INDENT]
- array_size
Данный параметр нужен для определения размера массива, который Вы передаёте в функцию в качестве параметра. Устанавливать его не нужно, ибо сервер всё сделает сам за Вас
(при неверной установке значения в данном массиве функция будет работать неверно!)
Открыть/закрыть Если текст, передающийся в функцию, находится в переменной с неизвестным числом ячеек (как в случае с диалогами и параметром inputtext), функция в любом случае будет заменять все "%" на "%".
Дабы такого не случилось, перед вызовом функции, запишите inputtext в любой массив. Например:
PHP код:
if(dialogid == 1111)
{
new inputtext_buff[145];//Объявляем массив
// 144+1 - именно столько (144) функция SendClientMessage(ToAll) сможет отправить символов за раз (1 - нуль-символ)
strcat(inputtext_buff, inputtext, 129);// Записываем содержимое inputtext в массив
//128+1 - именно столько (128) символов игрок может ввести в диалоговое окно (1 - нуль-символ)
FindSpecifiersInString(inputtext_buff);//Вызываем функцию
format(inputtext_buff, sizeof(inputtext_buff), "Ты написал: %s.", inputtext_buff);//Отображаем и, для экономии памяти, записываем текст в тот же массив (в данном случае такое приемлемо)
SendClientMessage(playerid, -1, inputtext_buff);// Отображаем
//В случае необходимости операцию можно повторять до бесконечности, а-ля
/*Хотя в данном случае лучше в format указать другой массив и тут уже использовать ранее записанные данные в inputtext_buff
но это ведь просто пример того, что функцию можно использовать несколько раз подряд для разного текста :)
strcat(inputtext_buff, inputtext, 129);
FindSpecifiersInString(inputtext_buff);
format(inputtext_buff, sizeof(inputtext_buff), "Он написал: %s.", inputtext_buff);
SendClientMessage(playerid, -1, inputtext_buff);*/
return 1;
}
И теперь функция будет обрабатывать все "%" как и положено
* Если указать "0", функция не будет пытаться сохранить "%" в первозданном виде, а сразу начнёт заменять все "%" на "#"
В ней учтено, что, в случае, если в SendClientMessage попадёт, например, "% s", или "% 000 s", или "%02d" - функция распознает данный текст как идентификатор и в SendClientMessage(ToAll) попадёт уже исправленная версия.
Пример использования:
PHP код:
main()
{
new string[13] = "% %% %s %%%";
FindSpecifiersInString(string, 0);//Все "%" заменит на "#"
printf("%s", string);
string = "% %% %s %%%";//Так как размер массива всего 13, а символов в строке 11, функция сможет сохранить только 2 первых символа, а всё остальное заменит на #
FindSpecifiersInString(string);//Продублирует все "%". В случае нехватки места начнёт заменять их на "#"
printf("%s", string);
}
Код функции с описанием
PHP код:
stock FindSpecifiersInString(message[], array_size = sizeof(message))//Во втором параметре узнаём размер массива, переданный в функцию
{
new message_length = strlen(message);//Узнаём размер строки, переданной в функцию
for(new i; i < message_length; i++)//Запускаем цикл на кол-во итераций, равное числу символов в строке
{
if(message[i] == '%')//Ищем символ "%"
{
if(message_length < array_size) strins(message, "%", i++, message_length++);
//Если нашли, проверяем наличие места в массиве и если свободные ячейки есть - добавляем новый символ, делая соответствующие
//Изменения в переменных
else message[i] = '#';//Если места нет, начинаем заменять "%" на "#"
}
}
}
P.S. Если попытаться в функции указать массив с неизвестным кол-вом ячеек (как в случае с параметром "inputtext" в OnDialogResponse), компилятор выплюнет предупреждение:
PHP код:
warning 224: indeterminate array size in "sizeof" expression (symbol "")
Я пока не придумал как это решить, но на работоспособность сей warning влиять не будет.
Если Вы знаете как обойти данную проблему, прошу отписаться по этому поводу ниже :)
Автор темы - DeimoS
Автор кода - DeimoS
Отдельная благодарность Daniel_Cortez
за ответы на идиотские вопросы с моей стороны :3
Специально для Pro-Pawn.ru
Копирование материала без указания авторства запрещено.
Ставь лайк, подписывайся на канал.
Ссылка на вебмани, а так же список всей музыки, использованной в видео, в описании.
Новое видео выложу после 1000 лайков :3