Гайд Убираем циклы и массивы с помощью стримера

vawylon

Участник
Автор темы
7
62
E_STREAMER_CUSTUM раскрываем потанцевал!

На примере возьмём систему домов.
Система домов записана в ассоциативный массив

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


C:
#define MAX_HOUSES 1000
enum h_data{
h_handle, // id дома
h_pickup_enter, // пикап вход в дом
h_pickup_exit, // пикап выход из дома
h_x,// позиция пикапа
h_y,// позиция пикапа
h_z// позиция пикапа
};
new house_data[MAX_HOUSE][h_data];

Возьмём штатную ситуацию: игрок подбирает пикап дома и мы как скриптеры начинаем проверять пикап вот таким способом
C:
public OnPlayerPickUpDynamicPickup(playerid, pickupid)
{
                for(new i; i<MAX_HOUSE; i++)
                {
                    if(pickupid == house[i][h_pickup_enter])
                    {
                        printf("Номер дома: %d", house_data[i][h_handle]);
                        break;
                    }
                }
}
Если закинуть на тест вот такой код станет ясно, немного медленно...

код выполнится 10.000 раз за 874 мл.сек - почти секунда!
C:
IsFind: 1
Tick count standart: 874

И теперь перейдём к самой функции из за которой и затеялся данный карнавал!
C:
Streamer_SetIntData(type, STREAMER_ALL_TAGS:id, data, value)
//type - тип объекта (объект,пикап,актёр...)
/*
STREAMER_TYPE_OBJECT (0)
STREAMER_TYPE_PICKUP (1)
STREAMER_TYPE_CP (2)
STREAMER_TYPE_RACE_CP (3)
STREAMER_TYPE_MAP_ICON (4)
STREAMER_TYPE_3D_TEXT_LABEL (5)
STREAMER_TYPE_AREA (6)
STREAMER_TYPE_ACTOR (7)

STREAMER_ALL_TAGS:id - id стримерского элемента.
data - "переменная" список стандартных:
*/
enum
{
        E_STREAMER_AREA_ID,
        E_STREAMER_ATTACHED_OBJECT,
        E_STREAMER_ATTACHED_PLAYER,
        E_STREAMER_ATTACHED_VEHICLE,
        E_STREAMER_ATTACH_OFFSET_X,
        E_STREAMER_ATTACH_OFFSET_Y,
        E_STREAMER_ATTACH_OFFSET_Z,
        E_STREAMER_ATTACH_R_X,
        E_STREAMER_ATTACH_R_Y,
        E_STREAMER_ATTACH_R_Z,
        E_STREAMER_ATTACH_X,
        E_STREAMER_ATTACH_Y,
        E_STREAMER_ATTACH_Z,
        E_STREAMER_COLOR,
        E_STREAMER_DRAW_DISTANCE,
        E_STREAMER_EXTRA_ID,
        E_STREAMER_HEALTH,
        E_STREAMER_INTERIOR_ID,
        E_STREAMER_INVULNERABLE,
        E_STREAMER_MAX_X,
        E_STREAMER_MAX_Y,
        E_STREAMER_MAX_Z,
        E_STREAMER_MIN_X,
        E_STREAMER_MIN_Y,
        E_STREAMER_MIN_Z,
        E_STREAMER_MODEL_ID,
        E_STREAMER_MOVE_R_X,
        E_STREAMER_MOVE_R_Y,
        E_STREAMER_MOVE_R_Z,
        E_STREAMER_MOVE_SPEED,
        E_STREAMER_MOVE_X,
        E_STREAMER_MOVE_Y,
        E_STREAMER_MOVE_Z,
        E_STREAMER_NEXT_X,
        E_STREAMER_NEXT_Y,
        E_STREAMER_NEXT_Z,
        E_STREAMER_PLAYER_ID,
        E_STREAMER_PRIORITY,
        E_STREAMER_ROTATION,
        E_STREAMER_R_X,
        E_STREAMER_R_Y,
        E_STREAMER_R_Z,
        E_STREAMER_SIZE,
        E_STREAMER_STREAM_DISTANCE,
        E_STREAMER_STYLE,
        E_STREAMER_SYNC_ROTATION,
        E_STREAMER_TEST_LOS,
        E_STREAMER_TYPE,
        E_STREAMER_WORLD_ID,
        E_STREAMER_X,
        E_STREAMER_Y,
        E_STREAMER_Z
}

Но мы будем использовать E_STREAMER_CUSTOM.

value - данные.
Так же можно использовать:
C:
native Streamer_GetFloatData(type, STREAMER_ALL_TAGS:id, data, &Float:result); // получить число с плавоющей точкой, Float тип
native Streamer_SetFloatData(type, STREAMER_ALL_TAGS:id, data, Float:value);  // установить число с плавоющей точкой, Float тип
native Streamer_GetIntData(type, STREAMER_ALL_TAGS:id, data);  // получить целое число
native Streamer_SetIntData(type, STREAMER_ALL_TAGS:id, data, value);  // установить целое число
native Streamer_RemoveIntData(type, STREAMER_ALL_TAGS:id, data);  // удалить "переменную"
native Streamer_HasIntData(type, STREAMER_ALL_TAGS:id, data); // существует ли что то в "переменной"
native Streamer_GetArrayData(type, STREAMER_ALL_TAGS:id, data, dest[], maxdest = sizeof dest); // получить массив
native Streamer_SetArrayData(type, STREAMER_ALL_TAGS:id, data, const src[], maxsrc = sizeof src); // записать массив
native Streamer_IsInArrayData(type, STREAMER_ALL_TAGS:id, data, value); // есть ли число в массиве
native Streamer_AppendArrayData(type, STREAMER_ALL_TAGS:id, data, value); //добавить данные в массив
native Streamer_RemoveArrayData(type, STREAMER_ALL_TAGS:id, data, value); // удалить значение value из массив
native Streamer_HasArrayData(type, STREAMER_ALL_TAGS:id, data); //существует ли массив
native Streamer_GetArrayDataLength(type, STREAMER_ALL_TAGS:id, data); //получить колличество элементов в массиве

Данные функции предназначены для изменения и получения данных будь это позиция,тип,текстура, какого либо стрим объекта (объект,пикап,актёр..) но с версией 2.9.5 появилась функция E_STREAMER_CUSTOM ранее была E_STREAMER_EXTRA_ID, которая даёт возможность нам "как бы прикрепить переменную к объекту" зная id объекта мы сможем получить как из моего примера id дома, появляется повод отказаться от циклов.
E_STREAMER_CUSTOM(0xFF) 0xFF - это наша как бы адрес переменной для объекта она должна быть уникальна.

C:
#define CUSTUM_HOUSEID 0xFF
#define E_STREAMER_HOUSE_PICKUP_ENTER   E_STREAMER_CUSTOM(CUSTUM_HOUSEID)

Модернизируем наш код...
C:
#define CUSTUM_HOUSEID 0xFF
#define E_STREAMER_HOUSE_PICKUP_ENTER   E_STREAMER_CUSTOM(CUSTUM_HOUSEID)
#define SetPickUpHouseHandle(%0,%1)            Streamer_SetIntData(STREAMER_TYPE_PICKUP, %0,  E_STREAMER_HOUSE_PICKUP_ENTER, %1)
#define GetPickUpHouseHandle(%0)               Streamer_GetIntData(STREAMER_TYPE_PICKUP, %0,  E_STREAMER_HOUSE_PICKUP_ENTER)
// STREAMER_TYPE_PICKUP - потому что мы работаем с пикапом;
/// SetPickUpHouseHandle(pickupid,value)
//.......
house[i][h_pickup_enter] = CreateDynamicPickup(1273, 2, house[i][h_x],house[i][h_y], house[i][h_z]);
SetPickUpHouseHandle(house[i][h_pickup_enter],i);
//.......
public OnPlayerPickUpDynamicPickup(playerid, pickupid)
{

        if(GetPickUpHouseHandle(pickupid) != 0) // примечание дома должны начинаться с 1, а не 0. 0 - не валидный дом!
        {
                printf("Номер дома: %d", GetPickUpHouseHandle(pickupid));
                return 1;
        }
}
Стример будет выбрасывать вот такое предупреждение
C:
*** Streamer Plugin: Streamer_GetIntData: Invalid data specified.

Это будет означать, что переменная не существует.
Перед использованием E_STREAMER_CUSTOM рекомендуют проверять существует ли вообще такой адрес Streamer_HasIntData.
Я просто отключу данное сообщение с помощью функции Streamer_ToggleErrorCallback(true); в GameModeInit или OnFilterScriptInit().

При тестировании сразу поймём, почему стоит использовать E_STREAMER_CUSTOM
C:
    new pickupid = house[998][h_pickup_enter];
        new = tick = GetTickCount();
        new bool:isfind;
        for(new loop; loop<10000; loop++)
        {
            if(GetPickUpHouseHandle(pickupid) == 998)
            {
                isfind = true;
            }
        }
        printf("IsFind: %d", isfind);
        printf("Tick count standart: %d", GetTickCount()-tick);
Результат

C:
IsFind: 1
Tick count custom: 2

Самому не верится, что в 400 раз быстрее делаем выводы.


Если посмотреть мои работы, они очень сырые и возможно данная статья сырая, так как полного знания терминов адрес это или переменная, как назвать правильно - не знаю. Я с удовольствием прочитаю отзыв каждого из вас, внесу правки. Возможно данный способ уже все используют. Не общаюсь с про скриптерами, но пока примеров с данным функционалом не встречал.
Какой я вижу потанцевал в этом?
Потенциал огромен. По сути мы можем использовать динамическую память стримера которую предоставил Y_Lees очень легко и просто.
Мы можем дать возможность игрокам выбрасывать предметы создавать их как объект и эти объекты не придётся заносить в массив. А потом бегать по массиву и искать является ли он предметом или нет, что это за объект. В этот момент чувствую себя неандертальцем с палкой в руке. Объект - есть переменная.
Так же мы можем привязывать группу объектов к объекту (под объектом имею введу любой элемент стримера) и удалять их синхронно. Создавать пикапы из нескольких объектов(элементов) вносить правки и другое как сказал без массивов и циклов.

C:
.....
        new Float:x, Float:y, Float:z, Float:distance;
        GetPlayerPos(playerid, x, y, z);
        new pickups[1];
        Streamer_GetAllVisibleItems(playerid, STREAMER_TYPE_PICKUP, pickups); // получаем список видимых пикапов сортируются по дистанции 0-самый ближайший. будем использовать самый ближайший хватит единичного размера
        if(GetPickUpHouseHandle(pickups[0]) != 0)
        {      
                Streamer_GetDistanceToItem(x,y,z, STREAMER_TYPE_PICKUP, pickups[0], distance, 3); // dimensions = 3 используем дистанцию по трём осям. можно убрать. стандарт - 3.
                if(distance < 3.0)
                {
                        printf("Рядом дом: %d", GetPickUpHouseHandle(pickups[0]));
                }
        }
}
.....


Автор я: vawylon
 
Последнее редактирование: