Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.
Страница 1 из 2 1 2 ПоследняяПоследняя
Показано с 1 по 10 из 17
  1. #1
    Аватар для Nexius_Tailer
    Пользователь

    Статус
    Оффлайн
    Регистрация
    04.01.2015
    Адрес
    Гомель, Беларусь
    Сообщений
    547
    Репутация:
    158 ±

    Эффективная реализация API инклуда с возможностью вызова функций из фильтрскриптов

    В этом уроке я расскажу, как умно сделать функционал (API) вашего инклуда, чтобы пользователи могли подключать инклуд к фильтрскриптам/моду и вызывать его внешние функции как из фильтрскриптов (но сами функции обрабатывались бы лишь в инклуде, подключенному к моду), так и из мода, но в этом случае с такой скоростью, как если бы они вызывались без поддержки их вызова из фильтрскриптов.

    В общем-то, вся суть алгоритма уже разложена в первом абзаце и при желании понимающим людям можно сразу переходить к последнему примеру реализации, а для всех остальных начну с самого начала.

    Прежде всего стоит прояснить, зачем вообще инклуду иметь API и для чего всё это нужно. API (внешние функции) некой системы в инклуде представляют собой функции, которые делаются, чтобы их могли использовать за пределами этого инклуда (в моде, фильтрскриптах, других инклудах). Простой пример - mxINI, easyDialogs/mdialog и т.д. Все эти инклуды имеют внутри себя функции, например ini_openFile или Dialog_Close, созданные специально для их использования извне. Таким образом, мы имеем движок нашего алгоритма (реализацию некой системы, её части) в отдельном файле, а из мода или других инклудов уже просто вызываем готовые функции в одну строчку. Либо же мы имеем в инклуде независимую систему, а функции нужны другим скриптам для доступа к её переменным (их узнавания/изменения) или любым другим данным. В случае с доступом к переменным можно, конечно, и не делать отдельных функций, а изменять эти переменные вне инклуда напрямую, но так обычно не принято по ряду причин и потому выделяемую память держат в зоне видимости лишь файла инклуда, давая к ней доступ другим скриптам через API функции.

    Хорошо. С тем, что такое и зачем нужно API нашему инклуду (если оно вам действительно нужно) разобрались. Теперь рассмотрим то, как на практике оно реализуется в большинстве случаев. Самый простой пример - в нашем инклуде создаётся stock функция -> в ней нужный нам код -> всё, функция готова для вызова из мода или любых других инклудов, также к нему подключенных. Однако в данном случае у нас не получится каким-либо образом вызывать эту функцию из любого другого фильтрскрипта. Вернее получится, если вы подключите этот же инклуд отдельно и к фильтрскрипту, но тем самым вы просто продублируете весь код инклуда ещё и для этого фильтрскрипта и в итоге будете иметь параллельную работу двух (всё равно не связанных между собой) систем из вашего инклуда в фильтрскрипте и в моде.

    Если в качестве api функций вы имеете что-то вроде этого:
    PHP код:
    stock IsValidVehicleModel(skinid) return (400 <= skinid <= 611);

    stock IsValidSkinModel(skinid) return (<= skinid <= 73 || 75 <= skinid <= 311);

    stock IsValidMapIconType(markertype) return (<= markertype <= 63);

    //И любые другие несложные функции, которые не обращаются к памяти и результат выполнения которых определяется проверками/вычислениями только лишь относительно заданных ей аргументов и ничего больше 

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

    Однако если вы имеете какую-либо более-менее полноценную систему в вашем инклуде с подобным функционалом:
    PHP код:
    new bool:IsChatEnabled[MAX_PLAYERS];

    public 
    OnPlayerConnect(playerid)
    {
        
    IsChatEnabled[playerid] = true;

        
    //Hook
        #if defined myinc_OnPlayerConnect
            
    return myinc_OnPlayerConnect(playerid);
        
    #else
            
    return 1;
        
    #endif
    }

    //Hook
    #if defined _ALS_OnPlayerConnect
        #undef OnPlayerConnect
    #else
        #define _ALS_OnPlayerConnect
    #endif
    #define OnPlayerConnect myinc_OnPlayerConnect
    #if defined myinc_OnPlayerConnect
        
    forward myinc_OnPlayerConnect(playerid);
    #endif

    public OnPlayerText(playeridtext[])
    {
        
    //Если IsChatEnabled равна false - блокируем отправку сообщений игрока в чат
        
    if(!IsChatEnabled[playerid]) return 0;

        
    //Hook
        #if defined myinc_OnPlayerText
            
    return myinc_OnPlayerText(playeridtext);
        
    #else
            
    return 1;
        
    #endif
    }

    //Hook
    #if defined _ALS_OnPlayerText
        #undef OnPlayerText
    #else
        #define _ALS_OnPlayerText
    #endif
    #define OnPlayerText myinc_OnPlayerText
    #if defined myinc_OnPlayerText
        
    forward myinc_OnPlayerText(playeridtext[]);
    #endif

    stock EnableChatForPlayer(playeridbool:enable)
    {
        if(!
    IsPlayerConnected(playerid)) return 0;
        
    IsChatEnabled[playerid] = enable;
        return 
    1;
    }

    stock IsChatEnabledForPlayer(playerid)
        return (
    IsPlayerConnected(playerid) ? IsChatEnabled[playerid] : 0); 

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

    Второй, более сложный пример реализации API функций уже с возможностью перенаправления их вызовов из фильтрскриптов в мод (т.е. наши функции, вызываясь в фильтрскриптах, не выполняются тут же в них, а всего лишь шлют удалённый вызов в инклуд, подключенный к моду, в котором находится уже непосредственно код этих функций) происходит следующим образом: мы создаём stock функции-"обёртки", в которых есть всего лишь функция CallRemoteFunction (клик) с вызовом другой паблик функции -> далее мы создаём эти самые паблик функции, которые в себе уже и содержат фактический код наших функций. CallRemoteFunction позволяет вызывать именно паблик функции (и именно поэтому нам приходится делать реальную функцию пабликом) всего лишь по её названию/указанным аргументам, ища и вызывая её по всем фильтрскриптам/моду уже в процессе работы сервера. Таким образом, благодаря CallRemoteFunction мы имеем возможность, вызвав функцию-обёртку в фильтрскрипте, послать сигнал на выполнение паблик функции с реальным кодом нашей функции уже в моде, тем самым выполняя код системы лишь в одном, едином месте. Удобно, но взамен мы жертвуем скоростью вызова этих функций, потому как CallRemoteFunction, выполняя вызов функции не напрямую, делает это достаточно медленно. Тем не менее, вот сам способ реализации этого варианта кодом, который используют почти во всех инклудах, где есть возможность вызывать функции инклуда из фильтрскриптов, выполняя их при этом в моде:
    PHP код:
    //На этот раз пример содержит не сами api функции некого инклуда,
    //а хуки обычных самповских нативов, которые также нам часто нужно перехватить и в моде и в скриптах,
    //однако код хука выполнить только в моде, перенаправляя вызовы из фильтрскриптов

    //Для начала давайте добавим те функции-обёртки, которые будут перенаправлять все вызовы в мод
    stock myinc_SetPlayerHealth(playeridFloat:health)
        return 
    CallRemoteFunction("myGMinc_SetPlayerHealth""if"playeridhealth);

    //Hook
    #if defined _ALS_SetPlayerHealth
        #undef SetPlayerHealth
    #else
        #define _ALS_SetPlayerHealth
    #endif
    #define SetPlayerHealth myinc_SetPlayerHealth

    stock myinc_SetPlayerArmour(playeridFloat:armour)
        return 
    CallRemoteFunction("myGMinc_SetPlayerArmour""if"playeridarmour);

    //Hook
    #if defined _ALS_SetPlayerArmour
        #undef SetPlayerArmour
    #else
        #define _ALS_SetPlayerArmour
    #endif
    #define SetPlayerArmour myinc_SetPlayerArmour

    //Теперь нам нужна часть инклуда, которая будет выполняться только в моде (т.е. только если не задефайнен FILTERSCRIPT)
    //В ней мы и объявим логику самой системы и наши паблик функции с фактическим кодом,
    //которые будут удалённо вызываться хукнутыми выше функциями

    #if !defined FILTERSCRIPT

    //Код системы, который должен выполняться только из мода
    new
        
    Float:PlayerHealth[MAX_PLAYERS],
        
    Float:PlayerArmour[MAX_PLAYERS];

    //Паблики с фактическим кодом перехваченных функций

    forward myGMinc_SetPlayerHealth(playeridFloat:health);
    public 
    myGMinc_SetPlayerHealth(playeridFloat:health)
    {
        if(!
    SetPlayerHealth(playeridhealth)) return 0//Валидация аргументов самой самповской функцией + её выполнение, если валидация прошла
        
    PlayerHealth[playerid] = health//Весь наш код
        
    return 1;
    }

    forward myGMinc_SetPlayerArmour(playeridFloat:armour);
    public 
    myGMinc_SetPlayerArmour(playeridFloat:armour)
    {
        if(!
    SetPlayerArmour(playeridarmour)) return 0//Валидация аргументов самой самповской функцией + её выполнение, если валидация прошла
        
    PlayerArmour[playerid] = armour//Весь наш код
        
    return 1;
    }

    //Ну а далее уже обнуление хп/брони при коннекте просто для демонстрации целостности системы из этого примера
    //Однако стоит заметить, что эта часть системы (как и любые другие, если таковые бы были далее)
    //также должна выполняться в части инклуда, доступной только из мода
    public OnPlayerConnect(playerid)
    {
        
    PlayerHealth[playerid] = 100.0;
        
    PlayerArmour[playerid] = 0.0;

        
    //Hook
        #if defined myinc_OnPlayerConnect
            
    return myinc_OnPlayerConnect(playerid);
        
    #else
            
    return 1;
        
    #endif
    }

    //Hook
    #if defined _ALS_OnPlayerConnect
        #undef OnPlayerConnect
    #else
        #define _ALS_OnPlayerConnect
    #endif
    #define OnPlayerConnect myinc_OnPlayerConnect
    #if defined myinc_OnPlayerConnect
        
    forward myinc_OnPlayerConnect(playerid);
    #endif

    #endif // !defined FILTERSCRIPT 

    Заметили, что реализация такого способа не потребовала создания двух отдельных инклудов: одного только для фильтрскриптов, а другого исключительно для мода? Всё в данном случае решила "#if !defined FILTERSCRIPT", тем самым один и тот же инклуд нам нужно просто подключить к моду и всем фильтрскриптам. Это тоже удобно и также используется многими достаточно давно, но при этом в таком случае важно иметь во всех фильтрскриптах перед подключением каких-либо инклудов дефайн "FILTERSCRIPT" в самом начале, таким образом давая этой системе работать правильно.

    И, вроде как, вот он выход из ситуации и решение проблемы, которым все пользуются уже достаточно долгое время: если нам нужны функции, которые должны мочь вызываться из фильтрскриптов, то мы делаем их вторым способом, а если нет - первым. Но что, если мы имеем достаточно объёмную систему, которая например, перехватывает большинство стандартных самповских нативов или имеет десятки/сотни API функций, для которых просто необходимо иметь возможность вызова из FS'а, но при этом, используя для них всех медленный CallRemoteFunction, мы совсем не можем быть уверенными, что конечный пользователь нашего инклуда имеет у себя вообще хоть какие-то фильтрскрипты? Это достаточно серьёзная проблема, потому как активное использование таких "перенаправляемых" функций из самого мода будет впустую замедлять весь сервер, а фича из второго способа, тем самым, превращается в абузу.

    Именно поэтому (+-) пару лет назад я сделал своё собственное решение на основе второго варианта, которое также позволяет вызывать наши API функции инклуда из фильтрскриптов (подключая инклуд к фильтрскриптам и перенаправляя функции в инклуд из мода) и при этом вызывая их напрямую из самого мода. Реальная оптимизация ощущается гораздо больше на практике, потому как чаще всего люди абсолютно не используют никакие фильтрскрипты либо используют их непродолжительное время, тем самым в таком большинстве случаев мы полностью снимаем нагрузку от CallRemoteFunction, хотя сама возможность вызова из фильтрскриптов никуда не пропадает и может быть добавлена в любом из подключенных фильтрскриптов даже прямо во время работы сервера.

    Итак, вот сама реализация такого метода на примере всё тех же хуков стандартных функций сампа:
    PHP код:
    //Для начала давайте снова добавим функции-обёртки, которые будут перенаправлять все вызовы в мод, но на этот раз...
    stock myinc_SetPlayerHealth(playeridFloat:health)
    {
        
    //мы тут же проверяем, где именно вызвалась наша функция-обёртка
        #if defined FILTERSCRIPT
            //и если это фильтрскрипт, то (куда деваться) перенаправляем вызов в мод через CallRemoteFunction
            
    return CallRemoteFunction("myGMinc_SetPlayerHealth""if"playeridhealth);
        
    #else
            //а вот если мод, то вызов паблика делаем напрямую, тем самым не теряя в скорости
            
    return myGMinc_SetPlayerHealth(playeridhealth);
        
    #endif
    }

    //Hook
    #if defined _ALS_SetPlayerHealth
        #undef SetPlayerHealth
    #else
        #define _ALS_SetPlayerHealth
    #endif
    #define SetPlayerHealth myinc_SetPlayerHealth

    //Здесь всё то же самое
    stock myinc_SetPlayerArmour(playeridFloat:armour)
    {
        
    #if defined FILTERSCRIPT
            
    return CallRemoteFunction("myGMinc_SetPlayerArmour""if"playeridarmour);
        
    #else
            
    return myGMinc_SetPlayerArmour(playeridarmour);
        
    #endif
    }

    //Hook
    #if defined _ALS_SetPlayerArmour
        #undef SetPlayerArmour
    #else
        #define _ALS_SetPlayerArmour
    #endif
    #define SetPlayerArmour myinc_SetPlayerArmour

    //Теперь нам нужна часть инклуда, которая будет выполняться только в моде (т.е. только если не задефайнен FILTERSCRIPT)
    //В ней мы и объявим наши паблик функции с фактическим кодом и логику самой системы

    #if !defined FILTERSCRIPT

    //Код системы, который должен выполняться только из мода
    new
        
    Float:PlayerHealth[MAX_PLAYERS],
        
    Float:PlayerArmour[MAX_PLAYERS];

    //Паблики с фактическим кодом перехваченных функций

    forward myGMinc_SetPlayerHealth(playeridFloat:health);
    public 
    myGMinc_SetPlayerHealth(playeridFloat:health)
    {
        if(!
    SetPlayerHealth(playeridhealth)) return 0//Валидация аргументов самой самповской функцией + её выполнение, если валидация прошла
        
    PlayerHealth[playerid] = health//Весь наш код
        
    return 1;
    }

    forward myGMinc_SetPlayerArmour(playeridFloat:armour);
    public 
    myGMinc_SetPlayerArmour(playeridFloat:armour)
    {
        if(!
    SetPlayerArmour(playeridarmour)) return 0//Валидация аргументов самой самповской функцией + её выполнение, если валидация прошла
        
    PlayerArmour[playerid] = armour//Весь наш код
        
    return 1;
    }

    //Ну а далее уже обнуление хп/брони при коннекте просто для демонстрации целостности системы из этого примера
    //Однако стоит заметить, что эта часть системы (как и любые другие, если таковые бы были далее)
    //также должна выполняться в части инклуда, доступной только из мода
    public OnPlayerConnect(playerid)
    {
        
    PlayerHealth[playerid] = 100.0;
        
    PlayerArmour[playerid] = 0.0;

        
    //Hook
        #if defined myinc_OnPlayerConnect
            
    return myinc_OnPlayerConnect(playerid);
        
    #else
            
    return 1;
        
    #endif
    }

    //Hook
    #if defined _ALS_OnPlayerConnect
        #undef OnPlayerConnect
    #else
        #define _ALS_OnPlayerConnect
    #endif
    #define OnPlayerConnect myinc_OnPlayerConnect
    #if defined myinc_OnPlayerConnect
        
    forward myinc_OnPlayerConnect(playerid);
    #endif

    #endif // !defined FILTERSCRIPT 

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

    А вот ещё один пример, только уже с собственными API функциями:
    PHP код:
    //И снова добавим функции-обёртки

    stock EnableChatForPlayer(playeridbool:enable)
    {
        
    //Валидацию аргументов на этот раз можно вынести сразу сюда,
        //чтобы не затрачивать время на перенаправление из фильтрскрипта функции, которая всё равно не выполнится
        
    if(!IsPlayerConnected(playerid)) return 0;
        
    #if defined FILTERSCRIPT
            
    return CallRemoteFunction("gm_EnableChatForPlayer""ii"playeridenable);
        
    #else
            
    return gm_EnableChatForPlayer(playeridenable);
        
    #endif
    }

    stock IsChatEnabledForPlayer(playerid)
    {
        
    //Валидацию аргументов на этот раз можно вынести сразу сюда,
        //чтобы не затрачивать время на перенаправление из фильтрскрипта функции, которая всё равно не выполнится
        
    if(!IsPlayerConnected(playerid)) return 0;
        
    #if defined FILTERSCRIPT
            
    return CallRemoteFunction("gm_IsChatEnabledForPlayer""i"playerid);
        
    #else
            
    return gm_IsChatEnabledForPlayer(playerid);
        
    #endif
    }

    //Часть инклуда, которая будет выполняться только в моде (т.е. только если не задефайнен FILTERSCRIPT) 

    #if !defined FILTERSCRIPT

    //Код системы, который должен выполняться только из мода
    new bool:IsChatEnabled[MAX_PLAYERS];

    //Паблики с фактическим кодом API функций

    forward gm_EnableChatForPlayer(playeridbool:enable);
    public 
    gm_EnableChatForPlayer(playeridbool:enable)
    {
        
    IsChatEnabled[playerid] = enable;
        return 
    1;
    }

    forward gm_IsChatEnabledForPlayer(playerid);
    public 
    gm_IsChatEnabledForPlayer(playerid) return IsChatEnabled[playerid];

    //Продолжение основного кода системы

    public OnPlayerConnect(playerid)
    {
        
    IsChatEnabled[playerid] = true;

        
    //Hook
        #if defined myinc_OnPlayerConnect
            
    return myinc_OnPlayerConnect(playerid);
        
    #else
            
    return 1;
        
    #endif
    }

    //Hook
    #if defined _ALS_OnPlayerConnect
        #undef OnPlayerConnect
    #else
        #define _ALS_OnPlayerConnect
    #endif
    #define OnPlayerConnect myinc_OnPlayerConnect
    #if defined myinc_OnPlayerConnect
        
    forward myinc_OnPlayerConnect(playerid);
    #endif

    public OnPlayerText(playeridtext[])
    {
        
    //Если IsChatEnabled равна false - блокируем отправку сообщений игрока в чат
        
    if(!IsChatEnabled[playerid]) return 0;

        
    //Hook
        #if defined myinc_OnPlayerText
            
    return myinc_OnPlayerText(playeridtext);
        
    #else
            
    return 1;
        
    #endif
    }

    //Hook
    #if defined _ALS_OnPlayerText
        #undef OnPlayerText
    #else
        #define _ALS_OnPlayerText
    #endif
    #define OnPlayerText myinc_OnPlayerText
    #if defined myinc_OnPlayerText
        
    forward myinc_OnPlayerText(playeridtext[]);
    #endif

    #endif // !defined FILTERSCRIPT 

    Ну а вместо итога я хотел бы привести плюсы и минусы реализации API последним (моим) вариантом.

    Плюсы:
    * Все функции в вашем инклуде доступны для вызова как из мода, так и из фильтрскриптов (как в предыдущем методе);
    * При этом нет большой нагрузки от вызова функций инклуда из мода, поскольку в этом случае они вызываются напрямую.

    Минусы:
    * Зависимость корректной работы всего этого алгоритма от того, добавил ли пользователь "#define FILTERSCRIPT" в начало каждого фильтрскрипта (как и в предыдущем методе);
    * Для каждой функции вы должны иметь её "обёртку" и паблик с фактическим её кодом, т.е. в сумме технически две функции для одной фактической (как в предыдущем методе);
    * Код становится ещё более некомпактным, чем в предыдущем методе, из-за постоянного дублирования проверок на фильтрскрипт внутри каждой функции-обёртки.

    Тем не менее, как мне кажется, это вполне того стоит и эффективность с лихвой перевешивают косметические недостатки.
    Последний раз редактировалось Nexius_Tailer; 22.06.2023 в 01:20.
    Не хотите постоянно проверять обновления моих скриптов?
    Подключите его последним, после всех остальных
    Nexius's Update Checker

  2. 3 пользователя(ей) сказали cпасибо:
    DeimoS (17.11.2019) execution (17.11.2019) Web (17.11.2019)
  3. #2
    Аватар для DeimoS
    Модератор?

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    5,588
    Репутация:
    1984 ±
    Чтоб всё не упиралось в макрос FILTERSCRIPT, можно сделать глобальную переменную и перехват OnGameModeInit. В перехвате устанавливаем для глобальной переменной единицу/true и уже вместо
    1. #if defined FILTERSCRIPT
    2. return CallRemoteFunction("gm_IsChatEnabledForPlayer", "i", playerid);
    3. #else
    4. return gm_IsChatEnabledForPlayer(playerid);
    5. #endif

    делаем
    1. if(глобальная_переменная == 0)
    2. return CallRemoteFunction("gm_IsChatEnabledForPlayer", "i", playerid);
    3. else
    4. return gm_IsChatEnabledForPlayer(playerid);


    Так как OnGameModeInit не вызывается для скриптов, у скриптов она будет равна нулю, а для мода - единице. Как итог, получится всё тот же принцип работы и независимость от наличия макроса FILTERSCRIPT, но в .amx будет попадать чуть больше кода + будет тратится чуть больше времени на проверки (хотя сравнение обычной переменной происходит настолько быстро, что это можно и не учитывать).
    Связаться со мной в VK можно через личные сообщения этой группы
    Заказы не принимаю

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

    Steve Pavlina

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

    Статус
    Оффлайн
    Регистрация
    04.01.2015
    Адрес
    Гомель, Беларусь
    Сообщений
    547
    Репутация:
    158 ±
    Цитата Сообщение от DeimoS Посмотреть сообщение
    Чтоб всё не упиралось в макрос FILTERSCRIPT, можно сделать глобальную переменную и перехват OnGameModeInit. В перехвате устанавливаем для глобальной переменной единицу/true и уже вместо
    1. #if defined FILTERSCRIPT
    2. return CallRemoteFunction("gm_IsChatEnabledForPlayer", "i", playerid);
    3. #else
    4. return gm_IsChatEnabledForPlayer(playerid);
    5. #endif

    делаем
    1. if(глобальная_переменная == 0)
    2. return CallRemoteFunction("gm_IsChatEnabledForPlayer", "i", playerid);
    3. else
    4. return gm_IsChatEnabledForPlayer(playerid);


    Так как OnGameModeInit не вызывается для скриптов, у скриптов она будет равна нулю, а для мода - единице. Как итог, получится всё тот же принцип работы и независимость от наличия макроса FILTERSCRIPT, но в .amx будет попадать чуть больше кода + будет тратится чуть больше времени на проверки (хотя сравнение обычной переменной происходит настолько быстро, что это можно и не учитывать).
    Да, тоже думал добавить такой вариант как альтернативу, но лично в своих скриптах это использовать не рискую. Проверки, переносящиеся в рантайм хоть и мизерные сами по себе, но в конечном итоге они будут присутствовать в самых частовызываемых событиях и функциях (а по факту вообще везде, куда дотянется инклуд: как в пабликах, так и в каждой api/хукнутой самп функции) и уже в глобальном плане, думаю, нагрузка будет более заметная. Тем более и выполняются эти проверки каждый раз почти в любом случае, что делает эту нагрузку постоянной на протяжении всей работы сервера.
    Не хотите постоянно проверять обновления моих скриптов?
    Подключите его последним, после всех остальных
    Nexius's Update Checker

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

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    5,588
    Репутация:
    1984 ±
    Цитата Сообщение от Nexius_Tailer Посмотреть сообщение
    Да, тоже думал добавить такой вариант как альтернативу, но лично в своих скриптах это использовать не рискую. Проверки, переносящиеся в рантайм хоть и мизерные сами по себе, но в конечном итоге они будут присутствовать в самых частовызываемых событиях и функциях (а по факту вообще везде, куда дотянется инклуд: как в пабликах, так и в каждой api/хукнутой самп функции) и уже в глобальном плане, думаю, нагрузка будет более заметная. Тем более и выполняются эти проверки каждый раз почти в любом случае, что делает эту нагрузку постоянной на протяжении всей работы сервера.
    Если сравнивать код без проверок и код с проверками, то да, нагрузка возрастёт на целых 100%! Но если говорить о нагрузке в целом, то она всё ещё будет крайне мала и несущественна (вся проверка будет генерировать около 5 инструкций). Даже в OnPlayerUpdate такой код никак не отразится на скорости работы сервера. Особенно относительно вызова CallRemoteFunction.


    Ну и чтоб не быть голословным, вот настройки для профайлера
      Открыть/закрыть
    1. // Profiler v1.3 (copyright (c) 2014-2017 Daniel_Cortez) \\ Pro-Pawn.ru
    2. // Условия использования данного кода: http://pro-pawn.ru/showthread.php?12585
    3.  
    4. /*======== Настройки =========================================================*/
    5. // Кол-во итераций в циклах.
    6. const PROFILER_ITERATIONS_MAJOR = 1_000_000;
    7. const PROFILER_ITERATIONS_MINOR = 10;
    8.  
    9. new const code_snippets_names[2][] =
    10. {
    11. {"if"},
    12. {"без if"}
    13. };
    14.  
    15.  
    16. #define Prerequisites();\
    17.   new pRaceActive;
    18.  
    19.  
    20. #define CodeSnippet0(); \
    21.   if(pRaceActive == 1){}else{}
    22.  
    23. #define CodeSnippet1();
    24.  
    25.  
    26.  
    27. /*======== Конец настроек ===================================================*/


    Результаты:





    Как видно, разница составляет около 100 тиков для 10 миллионов вызовов. Разделяем 100 на 10 миллионов и получаем 0.00001 тика. Повлияет ли это хоть как-то на сервер? Сомневаюсь. Даже если подключить 100 инклудов, в которых будут подобного рода проверки, нагрузка заметной никак не станет.
    Связаться со мной в VK можно через личные сообщения этой группы
    Заказы не принимаю

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

    Steve Pavlina

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

    Статус
    Оффлайн
    Регистрация
    04.01.2015
    Адрес
    Гомель, Беларусь
    Сообщений
    547
    Репутация:
    158 ±
    Цитата Сообщение от DeimoS Посмотреть сообщение
    Если сравнивать код без проверок и код с проверками, то да, нагрузка возрастёт на целых 100%!
    Я говорил совсем про другое.

    Цитата Сообщение от DeimoS Посмотреть сообщение
    Результаты:





    Как видно, разница составляет около 100 тиков для 10 миллионов вызовов. Разделяем 100 на 10 миллионов и получаем 0.00001 тика. Повлияет ли это хоть как-то на сервер? Сомневаюсь. Даже если подключить 100 инклудов, в которых будут подобного рода проверки, нагрузка заметной никак не станет.
    За тесты спасибо, но лично я бы всё равно предпочёл дефайн проверки даже просто чтобы не нести этот мусор в amx. Как-никак, наличие FILTERSCRIPT в начале любого fs'а это норма, которая, во-первых, присутствует в том числе и в new.pwn, ну и во-вторых, в интересах самого же пользователя для правильной работы всей той кучи остальных скриптов, которые уже его используют и вряд ли когда-то перестанут.

    А, и да, на практике есть проблема ещё с выделением глобальных переменных в части мода, имел бы такой инклуд рантайм проверки на фильтрскрипт. Дефайн-проверка в этом плане тупо отсечёт код независимо от того, находится ли он в теле функции/паблика или нет.
    Последний раз редактировалось Nexius_Tailer; 18.11.2019 в 22:45.
    Не хотите постоянно проверять обновления моих скриптов?
    Подключите его последним, после всех остальных
    Nexius's Update Checker

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

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    5,588
    Репутация:
    1984 ±
    Не знаю про какое повсеместное наличие макроса FILTERSCRIPT ты говоришь, ибо если зайти, например, в раздел скриптов этого форума и начать смотреть исходники, то можно удивиться тому, что скриптов без макроса, в лучшем случае, столько же, сколько и с макросом. Просто потому что большая часть скриптеров не очень понимает зачем он нужен.

    Но вообще я нигде не утверждал, что мой вариант лучше. Я просто указал на то, как реализовать всё иначе, озвучив основные плюсы и минусы такого подхода.
    Связаться со мной в VK можно через личные сообщения этой группы
    Заказы не принимаю

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

    Steve Pavlina

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

    Статус
    Оффлайн
    Регистрация
    04.01.2015
    Адрес
    Гомель, Беларусь
    Сообщений
    547
    Репутация:
    158 ±
    Цитата Сообщение от DeimoS Посмотреть сообщение
    Не знаю про какое повсеместное наличие макроса FILTERSCRIPT ты говоришь, ибо если зайти, например, в раздел скриптов этого форума и начать смотреть исходники, то можно удивиться тому, что скриптов без макроса, в лучшем случае, столько же, сколько и с макросом. Просто потому что большая часть скриптеров не очень понимает зачем он нужен.
    Не думаю, что на этом форуме есть достаточное количество релизов инклудов, которые имеют возможность подключаться к фильтрскриптам в принципе, так что лучше смотреть на официальном. А так, вариант вполне себе, тут уже даже скорее личный выбор каждого, что и как ему использовать для каких ситуаций, учитывая, что любая из альтернатив имеет свои нюансы.
    Последний раз редактировалось Nexius_Tailer; 19.11.2019 в 00:22.
    Не хотите постоянно проверять обновления моих скриптов?
    Подключите его последним, после всех остальных
    Nexius's Update Checker

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

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    5,588
    Репутация:
    1984 ±
    Цитата Сообщение от Nexius_Tailer Посмотреть сообщение
    Не думаю, что на этом форуме есть достаточное количество релизов инклудов, которые имеют возможность подключаться к фильтрскриптам в принципе, так что лучше смотреть на официальном. А так, вариант вполне себе, тут уже даже скорее личный выбор каждого, что и как ему использовать для каких ситуаций, учитывая, что любая из альтернатив имеет свои нюансы.
    Про данный форум я сказал сугубо в качестве примера, за которым не нужно "далеко ходить" :) Да и речь ведь не об инклудах, а о скриптах.

    К слову, зашёл сейчас ради интереса на официальный форум, перешёл в раздел скриптов и из первых десяти тем только в двух был макрос (+ещё в двух были мёртвые ссылки). Так что ситуация с этим макросом особо не изменилась, судя по всему) В любом случае, как я уже говорил, я ни на чём не настаиваю.
    Связаться со мной в VK можно через личные сообщения этой группы
    Заказы не принимаю

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

    Steve Pavlina

  11. #9
    Аватар для Nexius_Tailer
    Пользователь

    Статус
    Оффлайн
    Регистрация
    04.01.2015
    Адрес
    Гомель, Беларусь
    Сообщений
    547
    Репутация:
    158 ±
    А, ну под использованием дефайна я имел в виду именно инклуды, которые учитывая его меняют своё поведение. Если какой-то обычный рядовой нубо-скрипт вроде "мой первый фс Vip system" или ещё чего подобного его не имеет, то это и не удивительно.
    Не хотите постоянно проверять обновления моих скриптов?
    Подключите его последним, после всех остальных
    Nexius's Update Checker

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

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    5,588
    Репутация:
    1984 ±
    Цитата Сообщение от Nexius_Tailer Посмотреть сообщение
    А, ну под использованием дефайна я имел в виду именно инклуды, которые учитывая его меняют своё поведение. Если какой-то обычный рядовой нубо-скрипт вроде "мой первый фс Vip system" или ещё чего подобного его не имеет, то это и не удивительно.
    Так речь ведь о том, что этот макрос отсутствует далеко не только в "рядовых нубо-скриптах", а, скорее, чуть ли не повсеместно. Просто потому что мало кто понимает его предназначение.
    Собственно, для того я и предложил вариант без привязки к макросу, который относительно мало скриптеров использует.

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

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

    Steve Pavlina

 

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

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

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

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

Ваши права

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