Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.

Реклама


**Как получить V.I.P** (Перейти)
Чтобы заказать рекламу на Pro-Pawn.Ru, обращайтесь в Skype.
Баннерная реклама 200руб/мес, Текстовая 100руб/мес.
Страница 1 из 3 123 ПоследняяПоследняя
Показано с 1 по 10 из 23
  1. #1
    Аватар для DeimoS
    Модератор?

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    3,931
    Репутация:
    1502 ±

    Исправляем краш при попадании спецификатора "%s" в SendClientMessage(ToAll)

    И вновь я Вас категорически приветствую!
    (что-то нечасто это бывает...)





    Ни для кого не секрет (а может для кого-то и секрет), что в 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 
    imessage_lengthi++)
        {
            if(
    message[i] == '%')
            {
                if(
    message_length array_sizestrins(message"%"i++, message_length++);
                else 
    message[i] = '#';
            }
        }


    Функция имеет один обязательный параметр и один совсем "ненужный" параметр.
    1. message[]
      - собственно, массив(!) с текстом, в котором мы будем обрабатывать символы
    2. array_size
      Данный параметр нужен для определения размера массива, который Вы передаёте в функцию в качестве параметра. Устанавливать его не нужно, ибо сервер всё сделает сам за Вас (при неверной установке значения в данном массиве функция будет работать неверно!)
        Открыть/закрыть
      Если текст, передающийся в функцию, находится в переменной с неизвестным числом ячеек (как в случае с диалогами и параметром inputtext), функция в любом случае будет заменять все "%" на "%".

      Дабы такого не случилось, перед вызовом функции, запишите inputtext в любой массив. Например:
      PHP код:
      if(dialogid == 1111)
      {
          new 
      inputtext_buff[145];//Объявляем массив
          // 144+1 - именно столько (144) функция SendClientMessage(ToAll) сможет отправить символов за раз (1 - нуль-символ)
          
      strcat(inputtext_buffinputtext129);// Записываем содержимое inputtext в массив
          //128+1 - именно столько (128) символов игрок может ввести в диалоговое окно (1 - нуль-символ)
          
      FindSpecifiersInString(inputtext_buff);//Вызываем функцию
          
      format(inputtext_buffsizeof(inputtext_buff), "Ты написал: %s."inputtext_buff);//Отображаем и, для экономии памяти, записываем текст в тот же массив (в данном случае такое приемлемо)
          
      SendClientMessage(playerid, -1inputtext_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(string0);//Все "%" заменит на "#"
        
    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 imessage_lengthi++)//Запускаем цикл на кол-во итераций, равное числу символов в строке
        
    {
            if(
    message[i] == '%')//Ищем символ "%"
            
    {
                if(
    message_length array_sizestrins(message"%"i++, message_length++);
                    
    //Если нашли, проверяем наличие места в массиве и если свободные ячейки есть - добавляем новый символ, делая соответствующие
                    //Изменения в переменных
                
    else message[i] = '#';//Если места нет, начинаем заменять "%" на "#"
            
    }
        }



    P.S. Если попытаться в функции указать массив с неизвестным кол-вом ячеек (как в случае с параметром "inputtext" в OnDialogResponse), компилятор выплюнет предупреждение:
    PHP код:
    warning 224indeterminate array size in "sizeof" expression (symbol ""
    Я пока не придумал как это решить, но на работоспособность сей warning влиять не будет.
    Если Вы знаете как обойти данную проблему, прошу отписаться по этому поводу ниже :)




    Автор темы - DeimoS
    Автор кода - DeimoS

    Отдельная благодарность
    Daniel_Cortez
    за ответы на идиотские вопросы с моей стороны :3



    Специально для Pro-Pawn.ru
    Копирование материала без указания авторства запрещено.

    Ставь лайк, подписывайся на канал.
    Ссылка на вебмани, а так же список всей музыки, использованной в видео, в описании.
    Новое видео выложу после 1000 лайков :3
    Последний раз редактировалось DeimoS; 29.02.2016 в 19:00.
    Связаться со мной можно в личных сообщениях этой группы

    Широко известно, что идеи стоят 0.8333 цента каждая (исходя из рыночной цены 10 центов за дюжину).
    Великих идей полно, на них нет спроса.
    Воплощение идеи в законченную игру требует долгой работы,
    таланта, терпения и креативности, не говоря уж о затратах денег, времени и ресурсов.
    Предложить идею просто, воплотить – вот в чём проблема

    Steve Pavlina

  2. #2
    Аватар для $continue$
    Пользователь

    Статус
    Оффлайн
    Регистрация
    02.08.2014
    Адрес
    г. Киров (aka Вятка)
    Сообщений
    1,441
    Репутация:
    261 ±
    "Я нуб в павно - но и ты не компилятор (с) G-I"
    Что, за этакий стиль, переменную для счетчика цикла объявлять в одном for а использовать в другом for?
    В чем профит?

    Хотел бы я посмотреть как тебе отстреливают ногу за goto - СИшники.




    А, да, не охото вчитываться в код, с sizeof проблема в функции?
    Если да, то:
    PHP код:
    stock FindSpecifiersInString(message[], bool:mode falsearray_size sizeof(message))
    {
        new 
    message_length strlen(message);
        for(new 
    ijmessage_lengthi++)
        {
            
    FSIS_For_Start:
            if(
    message[i] == '%')
            {
                for(
    i+1<= message_lengthj++)
                {
                    switch(
    message[j])
                    {
                        case 
    '0'..'9'' ''.''#': continue;
                        default:
                        {
                            if(
    mode == true && array_size != && message_length array_size)
                            {
                                
    strins(message"%"imessage_length);
                                
    message_length++;
                                
    j;
                            }
                            else 
    message[i] -= 0x2;
                            
    i++;
                            goto 
    FSIS_For_Start;
                        }
                    }
                }
            }
        }

    Последний раз редактировалось $continue$; 29.02.2016 в 00:53.
    Value your freedom or you will lose it, teaches history. "Don't bother us with politics," respond those who don't want to learn. (c) Richard Stallman

  3. #3
    Аватар для DeimoS
    Модератор?

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    3,931
    Репутация:
    1502 ±
    Цитата Сообщение от $continue$ Посмотреть сообщение
    Что, за этакий стиль, переменную для счетчика цикла объявлять в одном for а использовать в другом for?
    В чем профит?
    Может для того, чтоб при каждой новой итерации в первом цикле не нужно было её инициализировать при старте второго, не? Хотя не удивлюсь, если ты прописываешь инициализацию переменных внутри циклов и считаешь это нормой.


    Цитата Сообщение от $continue$ Посмотреть сообщение
    Хотел бы я посмотреть как тебе отстреливают ногу за goto - СИшники.
    В данном случае без него я не нашёл способа реализовать всё правильно. Да и тут goto не переносит тебя на 1000 строк в совершенно другой участок мода, так что это не так смертельно.

    - - - Добавлено - - -

      Открыть/закрыть
    Цитата Сообщение от $continue$ Посмотреть сообщение
    "Я нуб в павно - но и ты не компилятор (с) G-I"
    Что, за этакий стиль, переменную для счетчика цикла объявлять в одном for а использовать в другом for?
    В чем профит?

    Хотел бы я посмотреть как тебе отстреливают ногу за goto - СИшники.




    А, да, не охото вчитываться в код, с sizeof проблема в функции?
    Если да, то:
    PHP код:
    stock FindSpecifiersInString(message[], bool:mode falsearray_size sizeof(message), message_length strlen(message))
    {
        for(new 
    ijmessage_lengthi++)
        {
            
    FSIS_For_Start:
            if(
    message[i] == '%')
            {
                for(
    i+1<= message_lengthj++)
                {
                    switch(
    message[j])
                    {
                        case 
    '0'..'9'' ''.''#': continue;
                        default:
                        {
                            if(
    mode == true && array_size != && message_length array_size)
                            {
                                
    strins(message"%"imessage_length);
                                
    message_length++;
                                
    j;
                            }
                            else 
    message[i] -= 0x2;
                            
    i++;
                            goto 
    FSIS_For_Start;
                        }
                    }
                }
            }
        }


    strlen прямо в параметрах функции? Окей, странный мальчик с третьей рукой из спины. Посмеёмся вместе когда компилятор крашнет :3

    И да, гений программирования, куда бы ты sizeof не запихал, компилятор выругается в любом случае, ибо проблема именно в том, что в функцию передаётся динамический массив (как в случае с inputtext). Возможно есть какая-то pragma или что-то ещё, но мне пока лень копать мат.часть и выискивать решение.
    Сап
    Связаться со мной можно в личных сообщениях этой группы

    Широко известно, что идеи стоят 0.8333 цента каждая (исходя из рыночной цены 10 центов за дюжину).
    Великих идей полно, на них нет спроса.
    Воплощение идеи в законченную игру требует долгой работы,
    таланта, терпения и креативности, не говоря уж о затратах денег, времени и ресурсов.
    Предложить идею просто, воплотить – вот в чём проблема

    Steve Pavlina

  4. #4
    Аватар для $continue$
    Пользователь

    Статус
    Оффлайн
    Регистрация
    02.08.2014
    Адрес
    г. Киров (aka Вятка)
    Сообщений
    1,441
    Репутация:
    261 ±
    1) Вынести за пределы for переменную, не?
    2) Не заметил, что используется strlen - отредактировал код, раньше чем ты ответил :3
    На счёт размера - действительно, может можно как то с помощью emit?
    Убогость - Pawn, ничего не поделать.
    Последний раз редактировалось $continue$; 29.02.2016 в 01:20.
    Value your freedom or you will lose it, teaches history. "Don't bother us with politics," respond those who don't want to learn. (c) Richard Stallman

  5. #5
    Аватар для DeimoS
    Модератор?

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    3,931
    Репутация:
    1502 ±
    Цитата Сообщение от $continue$ Посмотреть сообщение
    1) Вынести за пределы for переменную, не?
    2) Не заметил, что используется strlen - отредактировал код, раньше чем ты ответил :3
    На счёт размера - действительно, может можно как то с помощью emit?
    Убогость - Pawn, ничего не поделать.
    1) И что изменится? Переменные относятся конкретно к циклам и логично искать инициализацию именно в циклах, не?
    2) Не поверишь, но именно так выглядела функция изначально. Но решил перенести параметр array_size в переменную, дабы молодые умы не решили, что его тоже нужно указывать при вызове функции и не получилась из-за этого куча багов :3
    Связаться со мной можно в личных сообщениях этой группы

    Широко известно, что идеи стоят 0.8333 цента каждая (исходя из рыночной цены 10 центов за дюжину).
    Великих идей полно, на них нет спроса.
    Воплощение идеи в законченную игру требует долгой работы,
    таланта, терпения и креативности, не говоря уж о затратах денег, времени и ресурсов.
    Предложить идею просто, воплотить – вот в чём проблема

    Steve Pavlina

  6. #6
    Аватар для vovandolg
    Пользователь

    Статус
    Оффлайн
    Регистрация
    17.11.2015
    Адрес
    Stavropol
    Сообщений
    1,360
    Репутация:
    113 ±
    Так а в чём соль, знак будет показываться и без краша или это правильная рабочая заменка?
    А то как нубу не очень дошло что да зачем)
    [Anticheat]___Invisible Fly Hack
    [Anticheat]____Weapon/Ammo Hack
    [Function]______ResetPlayerWeaponSlot
    [Function]_______FIX_SetPlayerAmmo
    [ServerMod]______TDM | Zombie Apokalypse

  7. #7
    Аватар для SliM
    Пользователь

    Статус
    Оффлайн
    Регистрация
    06.11.2015
    Сообщений
    35
    Репутация:
    9 ±
    почему нельзя сделать так?
    PHP код:
    new message_length,
    array_size strlen(message);
    message_length strlen(message); 
    ____________________________UPD
    Сам догнал почему:)
    ____________________________
    Поэтому я решил написать свою функцию, которая, по возможности, сможет оставить все знаки вопроса в сообщении игрока
    Это опечатка? или я через строку читал, что за знаки вопроса?
    (как в случае с параметром "inputtext" в OnRequestClass)
    все таки в OnRequestClass не в OnDialogResponse?
    Последний раз редактировалось SliM; 29.02.2016 в 06:03.

  8. #8
    Аватар для DeimoS
    Модератор?

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    3,931
    Репутация:
    1502 ±
    Цитата Сообщение от SliM Посмотреть сообщение
    Это опечатка? или я через строку читал, что за знаки вопроса?

    все таки в OnRequestClass не в OnDialogResponse?
    Спасибо, исправил. 3 часа ночи было и немного начал "плыть" ;)

    - - - Добавлено - - -

    Цитата Сообщение от vovandolg Посмотреть сообщение
    Так а в чём соль, знак будет показываться и без краша или это правильная рабочая заменка?
    А то как нубу не очень дошло что да зачем)
    Есть функция SendClientMessage в которой ещё с мезозойских времён имеется вот такой баг:







    То бишь, если в функцию передать спецификатор (спецификатор - это "%s", "%d" и т.п.), который не был форматирован до этого в том же format, то сервер из-за этого упадёт (точнее, падает он, вроде, только от спецификатора "%s". Но про это я в теме говорил).
    Куй исправил тему с OnPlayerText и OnPlayerCommandText, обрабатывая введённый игроком текст и заменяя все "%" на "#", но с диалогами он этого не сделал (а это самый распространённый пример. Авось ещё где-то можно подобный баг провернуть).

    Эта функция является более функциональным аналогом тех вариаций, что гуляют в интернете (опять же, я об этом писал в теме: про способы, которые заменяют все "%" на "#"). Хотя что те варианты, что мой - все рабочие, хотя логичнее использовать мой, ибо тогда обрабатываться будут не все диалоги, а только нужные.

    P.S. Если я неправильно понял вопроса и ты спрашивал о том, как работает сей баг, который исправляет функция, вставь этот код:
    PHP код:
    public OnPlayerSpawn(playerid)
    {
        
    ShowPlayerDialog(playerid1112DIALOG_STYLE_INPUT"Crash""Crash""Да""Нет (Да)");
        return 
    1;
    }
    public 
    OnDialogResponse(playeriddialogidresponselistiteminputtext[])
    {
        if(
    dialogid == 1112)
        {
            new 
    inputtext_buff[145];
            
    strcat(inputtext_buffinputtext128);
            
    //FindSpecifiersInString(inputtext_buff, true);
            
    format(inputtext_buffsizeof(inputtext_buff), "Написал: %s."inputtext_buff);
            return 
    SendClientMessage(playerid, -1inputtext_buff);
        }
        return 
    1;

    А после попробуй ввести в это диалоговое окно что-то подобное
    PHP код:
    %%   %%
    И смотри что будет :)
    А потом убери комментирование строки с вызовом функции + вставь код самой функции из урока и посмотри что выйдет после

    - - - Добавлено - - -

    Да или просто в OnPlayerConnect добавь
    PHP код:
    SendClientMessage(playerid, -1"%s"); 
    И при первом вошедшем игроке на сервер, его просто крашнет
    Связаться со мной можно в личных сообщениях этой группы

    Широко известно, что идеи стоят 0.8333 цента каждая (исходя из рыночной цены 10 центов за дюжину).
    Великих идей полно, на них нет спроса.
    Воплощение идеи в законченную игру требует долгой работы,
    таланта, терпения и креативности, не говоря уж о затратах денег, времени и ресурсов.
    Предложить идею просто, воплотить – вот в чём проблема

    Steve Pavlina

  9. #9
    Аватар для Daniel_Cortez
    new fuck_logic[0] = EOS;

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    1,666
    Репутация:
    2145 ±
    1. sizeof нельзя использовать на массивах-параметрах функции.
    2. При вставке ещё одного символа "%" теряется символ в конце строки. Этого побочного эффекта в описании не указано.
    Индивидуально в PM и Skype по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).
    SA-MP 0.4 is a lie

  10. #10
    Аватар для DeimoS
    Модератор?

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    3,931
    Репутация:
    1502 ±
    Цитата Сообщение от Daniel_Cortez Посмотреть сообщение
    1. sizeof нельзя использовать на массивах-параметрах функции.
    2. При вставке ещё одного символа "%" теряется символ в конце строки. Этого побочного эффекта в описании не указано.
    1) При этом всё работает Правда, как уже писал в теме, компилятор выплёвывает warning в случае, если попытаться параметром передать массив с неизвестным числом ячеек, но тогда sizeof просто ровна нулю, на чём и построена проверка
    2) Так вставка происходит только если в массиве, переданном в функцию, имеется место, не? Именно для этого я и спрашивал у тебя насчёт sizeof и именно об этой проверке я написал в предыдущем пункте. Если длина текущей строки+1 новый символ не равно или больше размеру массива, полученного через sizeof - добавляем новый символ. Иначе заменяем "%" на "#"
    Связаться со мной можно в личных сообщениях этой группы

    Широко известно, что идеи стоят 0.8333 цента каждая (исходя из рыночной цены 10 центов за дюжину).
    Великих идей полно, на них нет спроса.
    Воплощение идеи в законченную игру требует долгой работы,
    таланта, терпения и креативности, не говоря уж о затратах денег, времени и ресурсов.
    Предложить идею просто, воплотить – вот в чём проблема

    Steve Pavlina

 

 
Страница 1 из 3 123 ПоследняяПоследняя

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •