Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.
Страница 1 из 5 1 2 3 ... ПоследняяПоследняя
Показано с 1 по 10 из 43
  1. #1
    Аватар для Daniel_Cortez
    "Это не хак, это фича"

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    2,192
    Репутация:
    2589 ±

    Перехват функций, часть 2: практика - пишем античит на HP

    Оглавление:


    Sup.
    В этой части мы рассмотрим создание простого античита на HP, подходящего к любому моду*.
    * За исключением тех, на которых уже есть аналогичный античит,
    в этом случае два разных античита могут конфликтовать друг с другом.


    Прежде, чем начать разбор примера, давайте рассмотрим несколько советов, которые помогут избежать самых распространённых ошибок, связанных с перехватами функций, и улучшить качество вашего кода.
    Внимание: данные советы ещё не рассматривались ни в одной из известных мне статей по перехватам (в.т.ч. в статье Y_Less'а на оффе). Поэтому, даже если Вы уже знакомы с техникой перехватов, эти советы достойны Вашего внимания.
    1. Внутри инклуда задавайте переменным и функциям (в т.ч. перехватываемым) один и тот же префикс, связанный с названием инклуда.
      Главное, чтобы этот префикс и названия переменных и функций в этом скрипте были уникальными, т.е. не повторялись в других инклудах и в основном скрипте.
      Также название префикса должно быть как можно менее общим. Плохие примеры: "ac", "fix".
      Античиты и багфиксы могут быть разные, поэтому старайтесь, отразить суть своего багфикса или античита. Например, "ac_spect__" (античит на невидимость, получаемую имитацией перехода в спект) (на самом деле, после "ac_hp" только 1 символ подчёркивания - это из-за ограничения названий до 31 символов в Pawn) или "ac_hp__" (античит на читерское HP).
      Если префиксы будут повторяться в разных перехватах, то эти перехваты будут конфликтовать друг с другом, что, в свою очередь, помешает компиляции скрипта.
      Пример: если есть инклуд "afk_system.inc", в котором реализована система AFK, можно использовать в нём префикс "afk_sys__" для перехватов, переменных, констант и функций (кроме тех функций, которые будут видны за пределами инклуда, например IsPlayerAFK).

    2. Перехватчик не должен менять аргументы перехватываемой функции, её логику работы и предназначение.
      Изменение возвращаемых значений допускается только в том случае, если это не нарушает совместимости с оригинальной функцией.
      Например, в античите на HP перехватчик GetPlayerHealth возвращает не то значение, которое возвратит оригинальная функция, а кол-во HP игрока, хранящееся в античите. Но в то же время перехватчик должен возвращать именно HP, а не сумму HP и брони или ещё что-нибудь, что поменяет логику работы функции.
      То же самое относится к изменению аргументов функции. Если с помощью перехвата добавить в какую-либо функцию дополнительные параметры, а потом убрать перехватчик, то компилятор будет выдавать ошибки и код не будет компилироваться без перехватчика, т.к. в оригинальной функции тех дополнительных параметров нет.
      Иными словами, работа перехватчика должна быть незаметной для того кода, который использует перехватываемую функцию, как будто того перехватчика и нет.
      Если же вам нужна функция, работающая по-другому - сделайте отдельную функцию, но не нужно путать её с оригиналом с помощью перехвата. Вмешательство в стандартную логику обычно приводит только к проблемам.

    3. Если название перехватываемой функции (в случае с коллбэками) или перехватчика (для нативных функций) длиннее 31 символов, его следует сократить до этого лимита. Сокращение производится путём отсечения лишних символов справа (например, ac_veh_hp__OnVehicleDamageStatusUpdate -> ac_veh_hp__OnVehicleDamageStatu), строго до длины в 31 символ (не больше и не меньше!).
      Пример:
      1. public OnVehicleDamageStatusUpdate(vehicleid, playerid)
      2. {
      3. // ...
      4. #if defined ac_veh_hp__OnVehicleDamageStatu // "урезаем" название до 31 символа
      5. ac_veh_hp__OnVehicleDamageStatu(vehicleid, playerid);
      6. #endif
      7. return 1;
      8. }
      9. #if defined _ALS_OnVehicleDamageStatusUpdat // "урезаем" название до 31 символа
      10. #undef OnVehicleDamageStatusUpdate
      11. #else
      12. #define _ALS_OnVehicleDamageStatusUpdat
      13. #endif
      14. #define OnVehicleDamageStatusUpdate ac_veh_hp__OnVehicleDamageStatu
      15. #if defined ac_veh_hp__OnVehicleDamageStatu
      16. forward ac_veh_hp__OnVehicleDamageStatu(vehicleid, playerid);
      17. #endif

    4. Всё, что должно использоваться только внутри инклуда (в данном уроке это переменные для записи HP - нельзя допустить, чтобы они изменялись из мода), должно иметь атрибут static.
      Пример:
      1. static some_var; // переменная не будет видна из мода
      2.  
      3. static stock DoSomething() // функция не будет видна из мода
      4. {
      5. // ...
      6. }

    5. Если перехватываемая функция не обязательно должна возвращать значение (пример: коллбэк OnPlayerConnect), вызывайте её из перехватчика следующим образом:
      1. #if defined LibName__Func
      2. LibName__Func();
      3. #endif
      4. return 1;

      Благодаря этому удастся избежать варнингов, если перехватываемая функция ничего не возвращает.
    6. Если в коде внутри перехватчика используются локальные переменные, ограничивайте этот код локальным блоком.
      1. public Func(param1, param2)
      2. {
      3. // локальные переменные ограничены локальным блоком
      4. {
      5. new string[256];
      6. // ...
      7. }
      8. #if defined LibName__Func
      9. return Libname_Func(param1, param2);
      10. #endif
      11. }

      Таким образом локальные переменные перехватчика не будут занимать место в стеке при вызове перехватываемой функции, благодаря чему перехватчики почти не будут потреблять дополнительного стекового пространства в моде.



    Перейдём обратно к заданию - написанию античита на HP.
    Сначала нужно определиться, как мы назовём инклуд с античитом и какой префикс будем использовать для переменных/функций.
    Для примера подойдёт название "ac_health.inc" или "ac_hp.inc". Соответственно, будем использовать префикс "ac_hp__".

    Дальше создадим массив, в который будем записывать здоровье игроков, устанавливаемое сервером:
    1. static Float:ac_hp__health[MAX_PLAYERS];

    Вместо new массив объявлен с помощью ключевого слова static - так, если перенести весь античит в отдельный инклуд, массив будет виден только внутри инклуда и не будет мешаться в моде.

    Дальше можно было бы найти все вызовы SetPlayerHealth и под ними дублировать устанавливаемое кол-во HP в ac_health__health:
    1. SetPlayerHealth(playerid, 100.0);
    2. ac_hp__health[playerid] = 100.0;

    НО для этого вам придётся:
    • Выискивать вручную все вызовы и точно так же вручную "прицеплять" к каждому из них дублирование HP в массив. И ни в коем случае не пропустить ни одного из них!
    • Всегда при использовании SetPlayerHealth держать в голове, что нужно добавить дублирование в ac_health.

    Кроме того, стоит помнить, что чем больше сделано модификаций кода, тем больше вероятность того, что туда вкрадётся какая-нибудь ошибка. Человеческий фактор.
    А может быть вы уже используете такой подход в своём RLS и даже не подозреваете, что в вашем античите на HP уже куча подобных ошибок, которые никогда не заметите ни вы, ни компилятор?
    Причём одна такая ошибка - и в один прекрасный момент недоантичит начнёт банить ни в чём не повинных игроков, а репутация проекта будет испорчена. Если же попытаетесь отыскать источник ошибки, столкнётесь с новой проблемой: забаненный игрок может не помнить всех подробностей (да и не факт, что он вообще что-то захочет говорить скриптеру) - придётся перепроверять каждый вызов SetPlayerHealth и устраивать кучу тестов на локальном сервере.

    Но ведь можно просто найти все вызовы SetPlayerHealth и под ними копировать устанавливаемое кол-во HP в ac_health!
    И именно поэтому такой подход всегда был и будет считаться быдлокодерством - абсолютно никаких гарантий надёжности и куча проблем, причину которых очень трудно найти. От человеческого фактора нельзя полностью избавиться, лучшее, что можно сделать - минимизировать риск, избавившись от дублирования кода.

    С техникой перехвата ситуация намного проще.
    Поскольку перехватчик всего один, достаточно лишь адекватно протестировать хотя бы 1 случай его использования.
    Затем во всех остальных случаях вызова SetPlayerHealth компилятор возьмёт всю рутинную работу по разбору перехватов на себя и перехватчик всегда будет вести себя так, как было запланировано.
    В результате вероятность возникновения ошибки сводится к нулю. Такой код поддерживать намного проще.

    Сделаем перехват функции SetPlayerHealth и в этом перехватчике осуществим дублирование выдаваемого кол-ва HP в массив:
    1. stock ac_hp__SetPlayerHealth(playerid, &Float:health)
    2. {
    3. ac_hp__health[playerid] = health;
    4. return SetPlayerHealth(playerid, health);
    5. }
    6. #if defined _ALS_SetPlayerHealth
    7. #undef SetPlayerHealth
    8. #else
    9. #define _ALS_SetPlayerHealth
    10. #endif
    11. #define SetPlayerHealth ac_hp__SetPlayerHealth


    Теперь нужно будет в функцию OnPlayerUpdate добавить проверку игрока на несанкционированное восстановление HP и последующую выдачу бана.
    Всё это, как вы уже могли догадаться, будет сделано с помощью перехватов.
    1. public OnPlayerUpdate(playerid)
    2. {
    3. // код перехвата вынесен в отдельный блок,
    4. { // чтобы после его выполнения переменные не занимали место в стеке
    5. new Float:health;
    6. GetPlayerHealth(playerid, health);
    7. // если кол-во HP изменилось с момента предыдущего обновления
    8. // сравниваемые значения трактуются, как целочисленные, чтобы избежать лишнего вызова floatcmp
    9. // (внимание! такой оптимизационный приём можно применять только при сравнении
    10. // с помощью знаков "==" и "!=", но ни в коем случае не с ">", "<", ">=" или "<=")
    11. if(_:ac_hp__health[playerid] != _:health)
    12. {
    13. // если игрок потерял HP, упав с высоты или с помощью чита - запоминаем новое значение
    14. // (пусть отнимает HP читами сколько угодно, всё равно восстановить его он уже не сможет)
    15. if(ac_hp__health[playerid] > health)
    16. {
    17. ac_hp__health[playerid] = health;
    18. }
    19. // если HP больше, чем записано в античите - HAX detected!
    20. else if(ac_hp__health[playerid] < health)
    21. {
    22. SetPlayerHealth(playerid, ac_hp__health[playerid]);
    23. }
    24. }
    25. }
    26. // на wiki.sa-mp.com написано, что возвращаемое коллбэком значение ни на что не влияет
    27. // и может быть пропущено, поэтому не стоит "требовать" это значение у перехватываемой функции -
    28. // вместо этого лучше использовать "return 1" отдельно от её вызова
    29. #if defined ac_hp__OnPlayerUpdate
    30. ac_hp__OnPlayerUpdate(playerid);
    31. #endif
    32. return 1;
    33. }
    34. #if defined _ALS_OnPlayerUpdate
    35. #undef OnPlayerUpdate
    36. #else
    37. #define _ALS_OnPlayerUpdate
    38. #endif
    39. #define OnPlayerUpdate ac_hp__OnPlayerUpdate
    40. #if defined ac_hp__OnPlayerUpdate
    41. forward ac_hp__OnPlayerUpdate(playerid);
    42. #endif


    Теперь сделаем перехват GetPlayerHealth. По идее он не обязателен и никак не отразится на работе античита.
    Но в случае с функцией GetPlayerHealth предоставляется возможность избавиться от вызова нативной функции, подменив её на функцию, написанную на Pawn - таким образом повысится производительность работы сервера при вызове функции.
    При этом на возвращаемом функцией значении это никак не отразится, т.к. античит теперь имеет полный контроль над HP игрока.
    1. stock ac_hp__GetPlayerHealth(playerid, &Float:health)
    2. {
    3. health = ac_hp__health[playerid];
    4. return 1;
    5. }
    6. #if defined _ALS_GetPlayerHealth
    7. #undef GetPlayerHealth
    8. #else
    9. #define _ALS_GetPlayerHealth
    10. #endif
    11. #define GetPlayerHealth ac_hp__GetPlayerHealth


    Внимание! Перехват OnPlayerUpdate следует делать выше перехватов GetPlayerHealth/SetPlayerHealth, иначе они будут влиять на работу перехватчика в OnPlayerUpdate, если в нём используются те функции.

    Но это ещё не всё. Если выдать игроку здоровье, оно выдастся ему не сразу из-за пинга.
    Античит проверит здоровье со следующим вызовом OnPlayerUpdate ещё до того, как здоровье обновится у игрока, в результате сервер запишет то кол-во HP, которое было ещё до выдачи.
    Как только у игрока обновится HP, в античите будет записано прежнее значение, и после ещё одной проверки в OnPlayerUpdate античит выдаст ложное срабатывание.
    Нужно исправить эту ситуацию. Сделаем так, чтобы античит игнорировал уменьшение HP у игрока в течение 1 секунды после выдачи.

    К переменным (под ac_hp__health):
    1. static ac_hp__ignore_timestamp[MAX_PLAYERS];


    Добавим перед переменными константу, в которой укажем время для игнорирования:
    1. #if !defined AC_HP__IGNORE_TIME
    2. #define AC_HP__IGNORE_TIME 1000
    3. #endif

    Почему вокруг объявления константы используется #if defined? Это мы разберём позже.
    А пока что добавим игнорирование в перехвате OnPlayerUpdate.
    Найдите строку:
    1. if(ac_hp__health[playerid] > health)

    и замените её на:
    1. if((ac_hp__health[playerid] > health)
    2. && (GetTickCount() > ac_hp__ignore_timestamp[playerid]))


    И остаётся лишь сделать запись времени, до которого античит будет игнорировать игрока.
    В перехвате SetPlayerHealth найдите строки:
    1. ac_hp__health[playerid] = health;
    2. return SetPlayerHealth(playerid, health);

    и замените их на:
    1. ac_hp__ignore_timestamp[playerid] = GetTickCount()+AC_HP__IGNORE_TIME;
    2. ac_hp__health[playerid] = health;
    3. return SetPlayerHealth(playerid, health);


    Теперь античит не будет выдавать ложных срабатываний при выдаче HP.
    Но остаётся ещё одна проблема: игрок будет умирать во время спавна.
    Суть в том, что при спавне у игрока всегда 100 HP, а в античите в это время записано 0.
    Если сервер не выдаст игроку новое кол-во HP, античит выдаст ложное срабатывание и установит игроку 0 HP.
    Чтобы исправить эту проблему, добавим под перехватом OnPlayerUpdate перехват OnPlayerSpawn, в котором запишем у игрока 100 HP.
    1. public OnPlayerSpawn(playerid)
    2. {
    3. ac_hp__ignore_timestamp[playerid] = GetTickCount()+AC_HP__IGNORE_TIME;
    4. ac_hp__health[playerid] = 100.0;
    5. #if defined ac_hp__OnPlayerSpawn
    6. ac_hp__OnPlayerSpawn(playerid);
    7. #endif
    8. return 1;
    9. }
    10. #if defined _ALS_OnPlayerSpawn
    11. #undef OnPlayerSpawn
    12. #else
    13. #define _ALS_OnPlayerSpawn
    14. #endif
    15. #define OnPlayerSpawn ac_hp__OnPlayerSpawn
    16. #if defined ac_hp__OnPlayerSpawn
    17. forward ac_hp__OnPlayerSpawn(playerid);
    18. #endif



    Итак, если игрок накручивает HP читами, античит будет понижать здоровье обратно.
    Но что, если нам нужно не только нейтрализовать читера, но и оповестить администрацию?
    Можно добавить после понижения здоровья вызов какой-нибудь функции из мода (например, SendAdminMessage) для вывода модераторам сообщения о читере, НО такая функция есть не везде, а потому модуль не будет работать на всех модах.
    Поэтому мы поступим иначе: добавим в мод коллбэк OnHPCheatDetected и в нём будем записывать весь код, который "привязан" к тому моду.
    Здесь же сделаем вызов коллбэка. В перехвате OnPlayerUpdate находим строку:
    1. SetPlayerHealth(playerid, ac_hp__health[playerid]);

    и заменяем её на:
    1. SetPlayerHealth(playerid, ac_hp__health[playerid]);
    2. #if defined OnHPCheatDetected
    3. OnHPCheatDetected(playerid, ac_hp__health[playerid], health);
    4. #endif

    И не забудем добавить опережающее объявление коллбэка для мода. В конец инклуда:
    1. #if defined OnHPCheatDetected
    2. forward OnHPCheatDetected(playerid, Float:hp_expected, Float:hp_got);
    3. #endif

    Обратите внимание: в обоих отрывках присутствует "#if defined" - это сделано для того, чтобы убедиться, что коллбэк OnHPCheatDetected реализован в моде.
    Если его в моде нет, он не будет вызван из инклуда - иначе были бы ошибки из-за вызова несуществующей функции.


    Наконец, составим весь код воедино и вынесем его в отдельный инклуд (например, "ac__health.inc", здесь "ac" - сокращение от "AntiCheat").
    Результат должен выглядеть примерно так, как в этой теме.

    В итоге получается система, совершенно никак не привязанная к конкретному моду.
    Поскольку она готова, остаётся лишь использовать её в вашем моде.
    Сохраним инклуд в папке "pawno/include" и подключим его:
    1. #include <dc_ac__health>

    После этого добавим в мод коллбэк OnHPCheatDetected, который уже сделан в инклуде:
    1. public OnHPCheatDetected(playerid, Float:hp_expected, Float:hp_got)
    2. {
    3. // здесь Ваш код для оповещения модераторов, бан игрока и т.д. и т.п.
    4. }


    Если у Вас получилось всё вышеперечисленное - поздравляю, Вы написали свой первый модуль на Pawn с использованием перехватов.
    К следующей неделе придумаю ещё несколько примеров для 3-й части урока.

    Автор: Daniel_Cortez

    Специально для Pro-Pawn.ru
    Копирование данной статьи на других ресурсах без разрешения автора запрещено!
    Индивидуально в ЛС по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).

  2. 16 пользователя(ей) сказали cпасибо:
    $continue$ (13.10.2014) BadPawn (29.02.2016) Battista (18.06.2016) codeo (14.10.2014) DeimoS (13.10.2014) Dima_Tushin (14.11.2014) L0ndl3m (13.10.2014) MassonNN (29.05.2020) Nurick (13.10.2014) Osetin (13.10.2014) Profyan (09.11.2014) qwezert (17.01.2017) Rasta (14.10.2014) Reim (12.07.2015) Salvacore (13.10.2014) Sp1ke (26.08.2015)
  3. #2
    Аватар для Dima_Tushin
    Пользователь

    Статус
    Оффлайн
    Регистрация
    21.04.2013
    Адрес
    Россия
    Сообщений
    154
    Репутация:
    1 ±
    Сейчас попробую сделать!

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

    а вот теперь все получилось и без ошибок! сейчас буду тестировать!
    Последний раз редактировалось Dima_Tushin; 13.10.2014 в 22:10.

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

    Статус
    Оффлайн
    Регистрация
    21.04.2013
    Адрес
    Россия
    Сообщений
    154
    Репутация:
    1 ±
    вчера я сделал но у меня не ловило читерское хп жалко блин ладно еще раз попробую!

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

    Статус
    Оффлайн
    Регистрация
    21.04.2013
    Адрес
    Россия
    Сообщений
    154
    Репутация:
    1 ±
    Помоги Daniel посмотри что я не правильного сделал?
      Открыть/закрыть
    PHP код:
    /*=============================================================================
            Health Anticheat
                by Daniel_Cortez

            www.pro-pawn.ru

    Copyright (c) 2014 Daniel_Cortez
    This software is provided 'as-is', without any express or implied warranty.
    In no event will the authors be held liable for any damages arising from the
    use of this software. Permission is granted to anyone to use this software for
    any purpose, including commercial applications, and to alter it and
    redistribute it freely, subject to the following restrictions:
        1.    The origin of this software must not be misrepresented; you must not
            claim that you wrote the original software. If you use this software in
            a product, an acknowledgment in the product documentation would be
            appreciated but is not required.
        2.    Altered source versions must be plainly marked as such, and must not be
            misrepresented as being the original software.
        3. This notice may not be removed or altered from any source distribution.
    =============================================================================*/
    static FloatHealth[MAX_PLAYERS];
    /************************************************/
    stock SetPlayerHealthAC(playeridFloathealthe)
    {
        
    Health[playerid] = healthe;
        return 
    SetPlayerHealth(playeridhealthe);
    }
    #if defined _ASC_SetPlayerHealth
    #undef SetPlayerHealth
    #else
    #define _ASC_SetPlayerHealth
    #endif
    #define SetPlayerHealth SetPlayerHealthAC
    /************************************************/
    public OnPlayerUpdate(playerid)
    {
        {
            new 
    Floathealth;
            
    GetPlayerHealth(playeridhealth);
            if((
    Health[playerid] != health))
            {
                if(
    Health[playerid] > health)
                {
                    
    Health[playerid] = health;
                
    #if defined OnHPCheatDetected
                    
    OnHPCheatDetected(playeridHealth[playerid], health);
                
    #endif 
                
    }
                else if(
    Health[playerid] < health)
                {
                    
    Health[playerid] = health;
                
    #if defined OnHPCheatDetected
                    
    OnHPCheatDetected(playeridHealth[playerid], health);
                
    #endif 
                
    }
            }
        }
    #if defined OnPlayerUpdateAC
        
    OnPlayerUpdateAC(playerid);
    #endif
        
    return 1;
    }
    #if    defined    _ALS_OnPlayerUpdate
        #undef    OnPlayerUpdate
    #else
        #define    _ALS_OnPlayerUpdate
    #endif
    #define    OnPlayerUpdate    OnPlayerUpdateAC
    #if    defined    OnPlayerUpdateAC
    forward OnPlayerUpdateAC(playerid);
    #endif
    /************************************************/
    public OnPlayerSpawn(playerid)
    {
        
    Health[playerid] = 100;
    #if defined OnPlayerSpawnAC
        
    OnPlayerSpawnAC(playerid);
    #endif
        
    return 1;
    }
    #if defined _ALS_OnPlayerSpawn
    #undef OnPlayerSpawn
    #else
    #define _ALS_OnPlayerSpawn
    #endif
    #define OnPlayerSpawn OnPlayerSpawnAC
    #if defined OnPlayerSpawnAC
    forward OnPlayerSpawnAC(playerid);
    #endif
    /************************************************/
    stock GetPlayerHealthAC(playerid, &Float:healths)
    {
        
    healths Health[playerid];
        return 
    1;
    }
    #if defined _ALS_GetPlayerHealth
    #undef GetPlayerHealth
    #else
    #define _ALS_GetPlayerHealth
    #endif
    #define GetPlayerHealth GetPlayerHealthAC
    /************************************************/
    #if defined OnHPCheatDetected
    forward OnHPCheatDetected(playeridFloat:hp_expectedFloat:hp_got);
    #endif 

    PHP код:
    GetPlayerHealth заменил GetPlayerHealthAC 
    PHP код:
    SetPlayerHealth заменил SetPlayerHealthAC в моде не в Include 
    помоги что то не правильно сделал поправь, подскажи
    Последний раз редактировалось Dima_Tushin; 14.10.2014 в 17:08.

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

    Статус
    Оффлайн
    Регистрация
    19.10.2013
    Адрес
    Ярославль
    Сообщений
    1,366
    Репутация:
    774 ±
    Самая большая ошибка в данном случае это присвоение работы за свою. :/
    Цитата Сообщение от Dima_Tushin Посмотреть сообщение
    /*=============================================================================
    Health Anticheat
    by Dima_Tuhin

    www.pro-pawn.ru

    Copyright (c) 2014 Dima_Tuhin
    И перечитайте ещё раз первый пост, заменять функции не стоит.

  7. Пользователь сказал cпасибо:
    Daniel_Cortez (14.10.2014)
  8. #6
    Аватар для Dima_Tushin
    Пользователь

    Статус
    Оффлайн
    Регистрация
    21.04.2013
    Адрес
    Россия
    Сообщений
    154
    Репутация:
    1 ±
    да это не важно я же не выкладываю и не говорю что я автор
    просто спросил в чем проблема

    да функции можно любые делать вот что обязательно в каждой переменной или функции делать пробелы вот такие ______
    Последний раз редактировалось Dima_Tushin; 14.11.2014 в 20:11.

  9. #7
    Аватар для Osetin
    •Администратор•

    Статус
    Оффлайн
    Регистрация
    26.03.2013
    Адрес
    ♔Osetia, Vladikavkaz♔
    Сообщений
    3,432
    Репутация:
    1093 ±
    Цитата Сообщение от Dima_Tushin Посмотреть сообщение
    да это не важно я же не выкладываю и не говорю что я автор
    просто спросил в чем проблема

    да функции можно любые делать вот что обязательно в каждой переменной или функции делать пробелы вот такие ______
    Как раз таки это важно. Люди старались, описывали вам все, а вы взяли и тупо сменили ник автора на свой ник. Т.е вы присвоили чужую работу, которую вам преподнесли с подробным разъяснением. А автор сидел несколько дней и пытался написать статью. Не очень приятно бывает, когда так поступают.

  10. #8
    Аватар для Dima_Tushin
    Пользователь

    Статус
    Оффлайн
    Регистрация
    21.04.2013
    Адрес
    Россия
    Сообщений
    154
    Репутация:
    1 ±
    на конец то получилось :) теперь все античиты переведу на Includе

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

    Цитата Сообщение от Osetin Посмотреть сообщение
    Как раз таки это важно. Люди старались, описывали вам все, а вы взяли и тупо сменили ник автора на свой ник. Т.е вы присвоили чужую работу, которую вам преподнесли с подробным разъяснением. А автор сидел несколько дней и пытался написать статью. Не очень приятно бывает, когда так поступают.
    ладно понял я больше не буду присваивать авторство!!!

  11. #9
    Аватар для Seregamil
    Проверенный

    Статус
    Оффлайн
    Регистрация
    21.11.2013
    Сообщений
    551
    Репутация:
    274 ±
    Цитата Сообщение от Dima_Tushin Посмотреть сообщение
    да это не важно я же не выкладываю и не говорю что я автор
    просто спросил в чем проблема

    да функции можно любые делать вот что обязательно в каждой переменной или функции делать пробелы вот такие ______
    Ахринеть, а давайте я хакну библиотеки сампа, и вместо "SA-MP Team" напишу "Seregamil"?

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

    Статус
    Оффлайн
    Регистрация
    02.08.2014
    Адрес
    г. Киров (aka Вятка)
    Сообщений
    1,487
    Репутация:
    276 ±
    Цитата Сообщение от Seregamil Посмотреть сообщение
    Ахринеть, а давайте я хакну библиотеки сампа, и вместо "SA-MP Team" напишу "Seregamil"?
    go cho

 

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

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

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

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

Ваши права

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