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

    Статус
    Оффлайн
    Регистрация
    17.11.2015
    Адрес
    Stavropol
    Сообщений
    1,369
    Репутация:
    113 ±

    ResetPlayerWeaponSlot

    Описание:
    Функция (ResetPlayerWeaponSlot) удаляющая оружие с выбранного слота

    Наверное все замечали что в SA:MP нету функции удаления оружия с выбранного слота,
    или может замечали такой момент когда истратив весь б/к в GetPlayerWeaponData
    нагло показывает что у Вас есть оружие, а патронов к нему "тю-тю",
    баг? или фича такая чтобы патроны потом пополнять? каждый по разному на это посмотрит.

    ResetPlayerWeaponSlot возвращает 2 значения(0,1)
    0 - Игрок не в сети
    1 - Слот успешно обнулён

    Код:
     Клац =3
    PHP код:
    #define MAX_SLOT_WEAP    (13) //макс. оружейных слотов

    stock ResetPlayerWeaponSlot(playeridslot//[slot 0-12]
    {
        if(
    IsPlayerConnected(playerid) == 0) return 0;
        goto 
    no_init_arrays;
        new 
    weapon[MAX_SLOT_WEAP], ammo[MAX_SLOT_WEAP], i_value;
    no_init_arrays:
        for(
    0MAX_SLOT_WEAPi++)
        {
            if(
    != slot)
            {
                
    GetPlayerWeaponData(playeridiweapon[i], ammo[i]);
            }
        }
        
    ResetPlayerWeapons(playerid);
        for(
    0MAX_SLOT_WEAPi++)
        {
            if((
    _value ammo[i]) != 0)
            {
                
    GivePlayerWeapon(playeridweapon[i], _value);
            }
        }
        return 
    1;



    Пример использования:
     Клац =3
    PHP код:
    CMD:resetslot(playeridparams[])
    {
        new 
    gunslot;
        if(
    sscanf(params"d"gunslot))
            return 
    SendClientMessage(playerid, -1, !"Использование: /resetslot [slot 0-12]");
        if(
    ResetPlayerWeaponSlot(playeridgunslot) == 0)
            return 
    SendClientMessage(playerid, -1, !"Игрок не в сети!");
        
    SendClientMessage(playerid, -1, !"Выбранный слот был обнулён!");
        return 
    1;



    Автор темы:
    vovandolg
    Помогали:
    VVWVV, Anton Styazhkin
    Последний раз редактировалось vovandolg; 03.08.2016 в 23:34.
    [Anticheat]___Invisible Fly Hack
    [Anticheat]____Weapon/Ammo Hack
    [Function]______ResetPlayerWeaponSlot
    [Function]_______FIX_SetPlayerAmmo
    [ServerMod]______TDM | Zombie Apokalypse

  2. Пользователь сказал cпасибо:
    HarrWe (30.08.2016)
  3. #2
    Аватар для VVWVV
    Модератор

    Статус
    Оффлайн
    Регистрация
    09.07.2015
    Сообщений
    728
    Репутация:
    347 ±
    - Вы не указали проверку на нахождения игрока в игре (IsPlayerConnected), а это означает, что все циклы, массивы будут инициализироваться/итерироваться без участия игрока.
    - Стоило бы вынести переменную "sl" из циклов, ибо переменная инициализируется несколько раз. (Зачем так называть переменную?)
    - Доступ к элементу массива очень затратный, поэтому стоило бы кешировать значение.

    Пример моей функции:
    PHP код:
    stock
        ResetPlayerWeaponSlot
    (playeridslot)
    {
        if (
    IsPlayerConnected(playerid) == 0)
            return 
    0;
        goto 
    no_init_arrays;
        new 
    weapon[MAX_WEAPON_SLOTS], ammo[MAX_WEAPON_SLOTS], i_value;
    no_init_arrays:
        for (
    0MAX_WEAPON_SLOTS; ++i)
        {
            if (
    == slot)
                continue;
            
    GetPlayerWeaponData(playeridiweapon[i], ammo[i]);
        }
        
    ResetPlayerWeapons(playerid);
        for (
    0!= MAX_WEAPON_SLOTS; ++i)
        {
            if ((
    _value ammo[i]) == 0)
                continue;
            
    GivePlayerWeapon(playeridweapon[i], _value);
        }
        return 
    1;

    Последний раз редактировалось VVWVV; 28.07.2016 в 05:14.

  4. #3
    Аватар для ziggi
    Проверенный

    Статус
    Оффлайн
    Регистрация
    14.05.2015
    Сообщений
    1,181
    Репутация:
    781 ±
    Цитата Сообщение от vovandolg Посмотреть сообщение
    Пару циклов на 13 итераций и 3 разных функции нам в помощь(ибо по другому не как):
    Ошибаешься, в fixes.inc эту проблему решили следующим образом:
    PHP код:
    stock FIX_GetPlayerWeaponData(playeridslot, &weapons, &ammo)
    {
        return
            
    slot GetPlayerWeaponData(playeridslotweaponsammo),
            
    weapons ammo weapons 0,
            
    slot;
    }
    #if defined _ALS_GetPlayerWeaponData
        #undef GetPlayerWeaponData
    #else
        #define _ALS_GetPlayerWeaponData
    #endif

    #define GetPlayerWeaponData FIX_GetPlayerWeaponData 
    То есть при вызове GetPlayerWeaponData проверяется наличие патронов и, если их 0, то weaponid передаётся в виде 0. Как мне кажется, так гораздо проще и эффективнее.
    Последний раз редактировалось ziggi; 28.07.2016 в 16:15.

  5. 2 пользователя(ей) сказали cпасибо:
    seriu (19.10.2016) Роуди. (28.07.2016)
  6. #4
    Аватар для vovandolg
    Пользователь

    Статус
    Оффлайн
    Регистрация
    17.11.2015
    Адрес
    Stavropol
    Сообщений
    1,369
    Репутация:
    113 ±
      Открыть/закрыть
    Цитата Сообщение от VVWVV Посмотреть сообщение
    - Вы не указали проверку на нахождения игрока в игре (IsPlayerConnected), а это означает, что все циклы, массивы будут инициализироваться/итерироваться без участия игрока.
    Я привык что у меня все такие проверки в команде или ещё где до работы этого кода, ну да ладно щас черканём..

    Цитата Сообщение от VVWVV Посмотреть сообщение
    - Стоило бы вынести переменную "sl" из циклов, ибо переменная инициализируется несколько раз. (Зачем так называть переменную?)
    Вот тут я не понял ты к моему невинному коду придрался
    sl - slot сокращённо, так я делал и мне так удобнее видеть было =3

    Цитата Сообщение от VVWVV Посмотреть сообщение
    - Доступ к элементу массива очень затратный, поэтому стоило бы кешировать значение.

    Пример моей функции:
    PHP код:
    stock
        ResetPlayerWeaponSlot
    (playeridslot)
    {
        if (
    IsPlayerConnected(playerid) == 0)
            return 
    0;
        goto 
    no_init_arrays;
        new 
    weapon[MAX_WEAPON_SLOTS], ammo[MAX_WEAPON_SLOTS], i_value;
    no_init_arrays:
        for (
    0MAX_WEAPON_SLOTS; ++i)
        {
            if (
    == slot)
                continue;
            
    GetPlayerWeaponData(playeridiweapon[i], ammo[i]);
        }
        
    ResetPlayerWeapons(playerid);
        for (
    0!= MAX_WEAPON_SLOTS; ++i)
        {
            if ((
    _value ammo[i]) == 0)
                continue;
            
    GivePlayerWeapon(playeridweapon[i], _value);
        }
        return 
    1;

    Можно ссылочку где про кеширование почитать можно?)

    Цитата Сообщение от ziggi Посмотреть сообщение
    Ошибаешься, в fixes.inc это проблему решили следующим образом:
    PHP код:
    stock FIX_GetPlayerWeaponData(playeridslot, &weapons, &ammo)
    {
        return
            
    slot GetPlayerWeaponData(playeridslotweaponsammo),
            
    weapons ammo weapons 0,
            
    slot;
    }
    #if defined _ALS_GetPlayerWeaponData
        #undef GetPlayerWeaponData
    #else
        #define _ALS_GetPlayerWeaponData
    #endif

    #define GetPlayerWeaponData FIX_GetPlayerWeaponData 
    То есть при вызове GetPlayerWeaponData проверяется наличие патронов и, если их 0, то weaponid передаётся в виде 0. Как мне кажется, так гораздо проще и эффективнее.
    Ну это как же я пропустил, то ли инклуд старый у меня...
    По крайней мере слоты заданные не очищает даже если там есть оружие, поэтому моя функция ещё в силе =3


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

    Ещё не понял момента в отрывке кода....
    Зачем вызывать лишний раз оператора
    PHP код:
    if (== slot)
        continue;
    GetPlayerWeaponData(playeridiweapon[i], ammo[i]); 
    Когда можно просто вот так сделать
    PHP код:
    if (!= slot)
        
    GetPlayerWeaponData(playeridiweapon[i], ammo[i]); 
    [Anticheat]___Invisible Fly Hack
    [Anticheat]____Weapon/Ammo Hack
    [Function]______ResetPlayerWeaponSlot
    [Function]_______FIX_SetPlayerAmmo
    [ServerMod]______TDM | Zombie Apokalypse

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

    Статус
    Онлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    5,360
    Репутация:
    1895 ±
    Цитата Сообщение от vovandolg Посмотреть сообщение
    Ещё не понял момента в отрывке кода....
    Зачем вызывать лишний раз оператора
    PHP код:
    if (== slot)
        continue;
    GetPlayerWeaponData(playeridiweapon[i], ammo[i]); 
    Когда можно просто вот так сделать
    PHP код:
    if (!= slot)
        
    GetPlayerWeaponData(playeridiweapon[i], ammo[i]); 
    Либо ты вызываешь "continue" явно, либо делаешь это неявно - разницы не вижу
    Связаться со мной в VK можно через личные сообщения этой группы

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

    Steve Pavlina

  8. #6
    Аватар для Desulaid
    лесоруб продакшен

    Статус
    Оффлайн
    Регистрация
    15.03.2015
    Адрес
    Slobodskoy
    Сообщений
    667
    Репутация:
    235 ±
    Цитата Сообщение от VVWVV Посмотреть сообщение
    - Вы не указали проверку на нахождения игрока в игре (IsPlayerConnected), а это означает, что все циклы, массивы будут инициализироваться/итерироваться без участия игрока.
    - Стоило бы вынести переменную "sl" из циклов, ибо переменная инициализируется несколько раз. (Зачем так называть переменную?)
    - Доступ к элементу массива очень затратный, поэтому стоило бы кешировать значение.

    Пример моей функции:
    PHP код:
    stock
        ResetPlayerWeaponSlot
    (playeridslot)
    {
        if (
    IsPlayerConnected(playerid) == 0)
            return 
    0;
        goto 
    no_init_arrays;
        new 
    weapon[MAX_WEAPON_SLOTS], ammo[MAX_WEAPON_SLOTS], i_value;
    no_init_arrays:
        for (
    0MAX_WEAPON_SLOTS; ++i)
        {
            if (
    == slot)
                continue;
            
    GetPlayerWeaponData(playeridiweapon[i], ammo[i]);
        }
        
    ResetPlayerWeapons(playerid);
        for (
    0!= MAX_WEAPON_SLOTS; ++i)
        {
            if ((
    _value ammo[i]) == 0)
                continue;
            
    GivePlayerWeapon(playeridweapon[i], _value);
        }
        return 
    1;

    Зачем пропускать инициализацию, если ты не получишь профита, но сделаешь код для других запутанней?

      Открыть/закрыть
    Цитата Сообщение от Daniel_Cortez Посмотреть сообщение
    Пропуск инициализации ячеек массива нулями.
    При объявлении локальных массивов внутри функций компилятор не только резервирует место в стеке под массив, но и инициализирует все его ячейки нулями, чтобы в них не было мусорных значений.
    Сделано это из-за быдлокодеров, которые, пользуются переменными, забывая их инициализировать.
    Тем не менее, инициализация занимает некоторое время, да и польза от этого сомнительная, если вы способны отдавать отчёт своим действиям.
    К счастью, есть способ избежать потерь во времени, пропустив инициализацию:
    PHP код:
        SomeFunction()
        {
            
    // перед объявлением массива перейдём на метку skip_array_init
            
    goto skip_array_init;
            
    // объявляем массив
            
    new arr[256];
        
    skip_array_init:
            
    // в этом месте массив arr будет существовать, но он не будет инициализирован:
            // код инициализации существует, но он находится _до_ метки skip_array_init,
            // т.е. мы обошли этот код

            // дальше - код с использованием массива
        

    Скомпилируем код, а затем дизассемблируем его.
    Получим следующую последовательность инструкций:
    Код HTML:
    	; Начало функции SomeFunction.
    	proc
    	; И сразу же - переход на метку l.0 (см. далее).
    	jump		0
    	; Выделение места в стеке под массив из 16 ячеек (ffffffc0 означает "-16")
    	; (этот код никогда не сработает, переход на l.0 был безусловным).
    	stack		ffffffc0
    	; Заполнение массива нулями происходит побайтово,
    	; 16 ячеек - 64 байта (40 в шестнадцатеричной системе счисления).
    	zero.pri
    	addr.alt	ffffffc0
    	fill		40
    ; Метка, с помощью которой пропускается инициализация массива.
    l.0
    	; Установка вершины стека в то положение, когда выделено 16 ячеек под массив,
    	; Обратите внимание: в отличие от обычного создания массива,
    	; здесь массив не заполняется никакими значениями,
    	; происходит только резервирование пространства,
    	lctrl		5
    	add.c		ffffffc0
    	sctrl		4
    	; Код с использованием массива.
    	; ...
    	; Высвобождение пространства в стеке и возврат из функции.
    	stack		40
    	zero.pri
    	retn
    Если кому интересно, вот тест скорости:
      Открыть/закрыть
    PHP код:
    #include <a_samp>

    const PROFILE_ITERATIONS_MAJOR 1000;
    const 
    PROFILE_ITERATIONS_MINOR 1000;

    const 
    STRING_SIZE 512;


    const 
    SZ STRING_SIZE;

    #define _m1();\
        
    {new a[SZ];}
    #define method1();\
        
    _m1();_m1();_m1();_m1();_m1();_m1();_m1();_m1();_m1();_m1();

    #define _m2();\
        
    {goto skip_init;new a[SZ];skip_init:}
    #define method2();\
        
    _m2();_m2();_m2();_m2();_m2();_m2();_m2();_m2();_m2();_m2();


    bool:IsJITEnabled()
    {
        
    #emit    lctrl    7
        #emit    retn
        
    return true;
    }

    main()
    {
        
    printf(
            
    "Testing array initialization..." "\n"\
            
    "(%dx%d iterations, array size: %d, JIT status: %sabled)",
            
    PROFILE_ITERATIONS_MAJORPROFILE_ITERATIONS_MINOR,
            
    STRING_SIZEIsJITEnabled() ? ("en") : ("dis")
        );
        new 
    t1t2tij;
        
    t1 0t2 0;
        for(
    0PROFILE_ITERATIONS_MAJOR; ++i)
        {
            
    GetTickCount();
            for(
    0PROFILE_ITERATIONS_MINOR; ++j)
            {
                
    method1();
                
    method1();
                
    method1();
                
    method1();
                
    method1();
                
    method1();
                
    method1();
                
    method1();
                
    method1();
                
    method1();
            }
            
    t1 += GetTickCount()-t;
            
    GetTickCount();
            for(
    0PROFILE_ITERATIONS_MINOR; ++j)
            {
                
    method2();
                
    method2();
                
    method2();
                
    method2();
                
    method2();
                
    method2();
                
    method2();
                
    method2();
                
    method2();
                
    method2();
            }
            
    t2 += GetTickCount()-t;
        }
        
    printf(
            
    "method 1: %d" "\n"\
            
    "method 2: %d",
            
    t1t2
        
    );


    Макросы method1 и method2 сделаны, чтобы повторить в них создание локальных массивов по 10 раз.
    Кроме того сами макросы используются в функции main по 10 раз (итого получается 10x10 = 100 повторов).
    Это не что иное, как развёртывание циклов. Я сделал именно так, чтобы уменьшить погрешность от циклов и вызовов GetTickCount, таким образом, увеличив точность измерений.
    Также в процессе компиляции выдаётся куча варнингов, но они, опять же, из-за макросов, не обращайте на них внимания.
    Тест я запускал на массивах из 32, 256 и 512 ячеек, с включенным и выключенным JIT.
    Результаты следующие:
      Открыть/закрыть

    Код:
    Testing array initialization...
    (1000x1000 iterations, array size: 32, JIT status: disabled)
    method 1: 5581
    method 2: 47
    
    Testing array initialization...
    (1000x1000 iterations, array size: 32, JIT status: enabled)
    method 1: 2640
    method 2: 4
    Код:
    Testing array initialization...
    (1000x1000 iterations, array size: 256, JIT status: disabled)
    method 1: 31324
    method 2: 42
    
    Testing array initialization...
    (1000x1000 iterations, array size: 256, JIT status: enabled)
    method 1: 15106
    method 2: 3
    Код:
    Testing array initialization...
    (1000x1000 iterations, array size: 512, JIT status: disabled)
    method 1: 63840
    method 2: 40
    
    Testing array initialization...
    (1000x1000 iterations, array size: 512, JIT status: enabled)
    method 1: 29161
    method 2: 4

    Из измерений можно сделать вывод, что размер массива никак не влияет на результаты метода с пропуском инициализации массива.
    Но всё же от трюка не сильно много пользы. Да, цифры в тесте, казалось бы, большие, но не стоит забывать, что они получены с помощью 100 миллионов итераций. В нормальных же условиях время инициализации массива в 512 ячеек составит всего ~0.0006384 мс или ~0.0000006 секунды.

  9. Пользователь сказал cпасибо:
    vovandolg (28.07.2016)
  10. #7
    Аватар для vovandolg
    Пользователь

    Статус
    Оффлайн
    Регистрация
    17.11.2015
    Адрес
    Stavropol
    Сообщений
    1,369
    Репутация:
    113 ±
    Так вот тут не пойму,
    no_init_arrays: будет пропускать инициализацию до ResetPlayerWeapons(playerid);
    или до конца всей функции?

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

    И зачем вот эта переменная _value
    [Anticheat]___Invisible Fly Hack
    [Anticheat]____Weapon/Ammo Hack
    [Function]______ResetPlayerWeaponSlot
    [Function]_______FIX_SetPlayerAmmo
    [ServerMod]______TDM | Zombie Apokalypse

  11. #8
    Аватар для Desulaid
    лесоруб продакшен

    Статус
    Оффлайн
    Регистрация
    15.03.2015
    Адрес
    Slobodskoy
    Сообщений
    667
    Репутация:
    235 ±
    Цитата Сообщение от vovandolg Посмотреть сообщение
    Так вот тут не пойму,
    no_init_arrays: будет пропускать инициализацию до ResetPlayerWeapons(playerid);
    или до конца всей функции?

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

    И зачем вот эта переменная _value
    1. Просто "перепрыгнем" через заполнение массива нулями. "Прыжок" буде с goto no_init_arrays; на "no_init_arrays:".
    2. Обращаться к элементу массива затратно. Этого можно избежать, если при одном из вызовов сохранить значение элемента в переменную и дальше уже пользоваться переменной со значением элемента массива.

  12. Пользователь сказал cпасибо:
    vovandolg (28.07.2016)
  13. #9
    Аватар для vovandolg
    Пользователь

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

  14. #10
    Аватар для Desulaid
    лесоруб продакшен

    Статус
    Оффлайн
    Регистрация
    15.03.2015
    Адрес
    Slobodskoy
    Сообщений
    667
    Репутация:
    235 ±
    Цитата Сообщение от vovandolg Посмотреть сообщение
    Ну и)) наинициализировались?
    VVWVV просто забыл кое что добавить. Бывает)

    Код:
    stock
        ResetPlayerWeaponSlot(playerid, slot)
    {
        if (IsPlayerConnected(playerid) == 0)
            return 0;
        goto no_init_arrays;
        new weapon[MAX_WEAPON_SLOTS], ammo[MAX_WEAPON_SLOTS], i, _value;
        no_init_arrays:
        for (i = 0; != MAX_WEAPON_SLOTS; ++i)
        {
            if (i == slot)
                continue;
            GetPlayerWeaponData(playerid, i, weapon[i], ammo[i]);
        }
        ResetPlayerWeapons(playerid);
        for (i = 0; i != MAX_WEAPON_SLOTS; ++i)
        {
            if ((_value = ammo[i]) == 0)
                continue;
            GivePlayerWeapon(playerid, weapon[i], _value);
        }
        return 1;
    }

  15. Пользователь сказал cпасибо:
    vovandolg (29.07.2016)
 

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

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

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

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

Ваши права

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