Дополнительные функции стримера / Функции манипуляции данными [Часть 1]
Вторая часть: перейти.
Третья часть: перейти.
Дисклеймер
Эта статья исключительно для тех, кто заинтересован в более глубоком изучении дополнительного функционала стримера, и не рекомендуется к прочтению, если вы используете его только для того, чтобы ставить через него свой маппинг на сервер и дальше этого он вам не нужен. Актуально для последних версий стримера (2.8.2 - 2.9.4).
Предисловие
Как-то раз я столкнулся с проблемой, когда мне нужна была какая-то очень редкоиспользуемая функция, нативка которой была для обычных объектов, но аналога которой для стримерских объектов не нашлось. Потом столкнулся с этой проблемой ещё и ещё раз, пока не решил изучить некоторые дополнительные функции стримера, которые довольно легко позволяют проделывать абсолютно любые действия над любым стримерским стаффом самостоятельно, даже если отдельных функций в стримере для этого нет.
Кстати, если вы здесь именно поэтому, то есть нуждаетесь в каком-либо функционале, коего вы не можете найти в стримере в качестве отдельных выделенных функций, то могу порекомендовать очень полезный include Streamer Functions (кликабельно), в котором есть абсолютно всё что вам нужно, и который, собственно, стал поводом для написания данной статьи.
Далее речь пойдёт о самых, по моему мнению, важных второстепенных функциях стримера, а также подробное описание, как ими пользоваться (чтобы далее вы сами могли использовать их абсолютно где хотите, понимая то, где их использование будет действительно выгодным и нужным). В первой части, в особенности, будет знакомство с функциями манипуляции данными.
Также это будет полезно для вас, если вы пишете какой-либо серверный модуль (include, fs), где вам нужно реализовать некую совместимость или более тесное взаимодействие со стримером. Ну или же если вы просто хотите узнать, например, как настроить лимиты для стримерских зон (которых по умолчанию нет), как поменять модель уже созданного актёра без его пересоздания (и соответственно возможного смещения его ида), или как узнать иды ближайших к игроку объектов без единого цикла с вашей стороны.
Определения (макросы)
для стримерских элементов
Мы уже поняли, что нам нужно будет как-то взаимодействовать с любыми элементами стримера (далее будем называть элементами всё, что может быть создано через стример). Потому для начала азы. Мы будем в основном иметь функции общего предназначения, в которых уже будем в самом начале указывать, для чего именно мы хотим что-либо узнать или поменять.
Список чего-либо виден ниже:
PHP код:
#define STREAMER_TYPE_OBJECT (0) //Этот макрос мы будем писать, когда нужно будет изменить какие-то данные для объекта
#define STREAMER_TYPE_PICKUP (1) //Этот для пикапов
#define STREAMER_TYPE_CP (2) //Для чекпоинтов
#define STREAMER_TYPE_RACE_CP (3) //Для гоночных чекпоинтов
#define STREAMER_TYPE_MAP_ICON (4) //Для мап-иконок (иконок на карте)
#define STREAMER_TYPE_3D_TEXT_LABEL (5) //Для 3D-текстов
#define STREAMER_TYPE_AREA (6) //Для стримерских зон
#define STREAMER_TYPE_ACTOR (7) //Для актёров
Почему выше в комментариях не написано, что типы именно для стримерских объектов, именно стримерских актёров или именно стримерских чекпоинтов? Потому что в некоторых функциях стример может работать также и с идами обычных объектов/актёров/чего-то ещё, если вдруг это понадобится, но об этом позже. В общем эти типы дают понять стримеру то, что ваш переданный ему далее ID 5 это именно ид (стримерского) пикапа, а не (стримерского) объекта или (стримерского) 3D-текста, если, к примеру, как тип вы передали именно "STREAMER_TYPE_PICKUP".
Перечисление
того, что можно установить стримерским элементам
Уже знаем, что первым аргументом в большинстве функций будет конкретный тип элемента. Вторым аргументом, логично предположить, будет сам ид элемента. Хорошо, но как нам понять, какие именно данные этому иду можно будет установить или их узнать?
Ниже показан enum, перечисляющий все данные, которые могут быть установлены большинством второстепенных функций стримера:
PHP код:
enum
{
E_STREAMER_AREA_ID, //(Int) (Array) Тип данных для установки/узнавания, при котором выбранный элемент будет отображаться только в данной(ых) стримерской(их) зоне(ах) либо будет узнано, внутри какой(их) стримерской(их) зоны(ах) отображается элемент
E_STREAMER_ATTACHED_OBJECT, //(Int) Тип, при котором выбранный элемент будет прикреплён (приаттачен) к объекту либо будет узнан ID объекта, к которому он приаттачен
E_STREAMER_ATTACHED_PLAYER, //(Int) Выбранный элемент будет прикреплён (приаттачен) к игроку либо будет узнан ID игрока, к которому он приаттачен
E_STREAMER_ATTACHED_VEHICLE, //(Int) Выбранный элемент будет прикреплён (приаттачен) к машине либо будет узнан ID машины, к которой он приаттачен
E_STREAMER_ATTACH_OFFSET_X, //(Float) Тип данных, при котором производится редактирование/узнавание смещений аттача по координате X
E_STREAMER_ATTACH_OFFSET_Y, //(Float) Редактирование/узнавание смещений аттача по координате Y
E_STREAMER_ATTACH_OFFSET_Z, //(Float) Редактирование/узнавание смещений аттача по координате Z
E_STREAMER_ATTACH_R_X, //(Float) Редактирование/узнавание координат аттача по вращению X
E_STREAMER_ATTACH_R_Y, //(Float) Редактирование/узнавание координат аттача по вращению Y
E_STREAMER_ATTACH_R_Z, //(Float) Редактирование/узнавание координат аттача по вращению Z
E_STREAMER_ATTACH_X, //(Float) Узнавание координат аттача по X
E_STREAMER_ATTACH_Y, //(Float) Узнавание координат аттача по Y
E_STREAMER_ATTACH_Z, //(Float) Узнавание координат аттача по Z
E_STREAMER_COLOR, //(Int) Редактирование/узнавание цвета элемента (map-иконки, 3D-текста)
E_STREAMER_DRAW_DISTANCE, //(Float) Редактирование/узнавание дистанции прорисовки элемента
E_STREAMER_EXTRA_ID, //(Int) (Array) Редактирование/узнавание своей собственной информации, которая будет закреплена за элементом
E_STREAMER_HEALTH, //(Float) Редактирование/узнавание кол-ва здоровья (актёра)
E_STREAMER_INTERIOR_ID, //(Int) (Array) Редактирование/узнавание интерьера(ов)
E_STREAMER_INVULNERABLE, //(Int) Редактирование/узнавание неуязвимости (актёра)
E_STREAMER_MAX_X, //(Float) Редактирование/узнавание максимальной координаты X (гангзоны, стримерской зоны)
E_STREAMER_MAX_Y, //(Float) Редактирование/узнавание максимальной координаты Y (гангзоны, стримерской зоны)
E_STREAMER_MAX_Z, //(Float) Редактирование/узнавание максимальной координаты Z (стримерской зоны)
E_STREAMER_MIN_X, //(Float) Редактирование/узнавание минимальной координаты X (гангзоны, стримерской зоны)
E_STREAMER_MIN_Y, //(Float) Редактирование/узнавание минимальной координаты Y (гангзоны, стримерской зоны)
E_STREAMER_MIN_Z, //(Float) Редактирование/узнавание минимальной координаты Z (стримерской зоны)
E_STREAMER_MODEL_ID, //(Int) Редактирование/узнавание ID'а модели элемента
E_STREAMER_MOVE_R_X, //(Float) Редактирование/узнавание финишной координаты движения вращения X (объекта)
E_STREAMER_MOVE_R_Y, //(Float) Редактирование/узнавание финишной координаты движения вращения Y (объекта)
E_STREAMER_MOVE_R_Z, //(Float) Редактирование/узнавание финишной координаты движения вращения Z (объекта)
E_STREAMER_MOVE_SPEED, //(Float) Редактирование/узнавание скорости движения (объекта)
E_STREAMER_MOVE_X, //(Float) Редактирование/узнавание финишной координаты движения X (объекта)
E_STREAMER_MOVE_Y, //(Float) Редактирование/узнавание финишной координаты движения Y (объекта)
E_STREAMER_MOVE_Z, //(Float) Редактирование/узнавание финишной координаты движения Z (объекта)
E_STREAMER_NEXT_X, //(Float) Редактирование/узнавание следующей координаты X (гоночного чекпоинта)
E_STREAMER_NEXT_Y, //(Float) Редактирование/узнавание следующей координаты Y (гоночного чекпоинта)
E_STREAMER_NEXT_Z, //(Float) Редактирование/узнавание следующей координаты Z (гоночного чекпоинта)
E_STREAMER_PLAYER_ID, //(Int) (Array) Редактирование/узнавание игрока(ов), которому(ым) будет виден элемент
E_STREAMER_PRIORITY, //(Int) Редактирование/узнавание приоритета элемента
E_STREAMER_ROTATION, //(Float) Редактирование/узнавание координаты вращения Z (угла поворота актёра)
E_STREAMER_R_X, //(Float) Редактирование/узнавание координаты вращения X
E_STREAMER_R_Y, //(Float) Редактирование/узнавание координаты вращения Y
E_STREAMER_R_Z, //(Float) Редактирование/узнавание координаты вращения Z
E_STREAMER_SIZE, //(Float) Редактирование/узнавание размера элемента (чекпоинта, гоночного чекпоинта, стримерской зоны)
E_STREAMER_STREAM_DISTANCE, //(Float) Редактирование/узнавание дистанции появления элемента
E_STREAMER_STYLE, //(Int) Редактирование/узнавание стиля (map-иконки)
E_STREAMER_SYNC_ROTATION, //(Int) Редактирование/узнавание синхронизации вращения (это параметр SyncRotation в функции AttachObjectToObject)
E_STREAMER_TEST_LOS, //(Int) Редактирование/узнавание видимости сквозь объекты (3D-текстов)
E_STREAMER_TYPE, //(Int) Редактирование/узнавание типа (map-иконки, пикапа, гоночного чекпоинта)
E_STREAMER_WORLD_ID, //(Int) (Array) Редактирование/узнавание виртуального(ых) мира(ов)
E_STREAMER_X, //(Float) Редактирование/узнавание координаты X
E_STREAMER_Y, //(Float) Редактирование/узнавание координаты Y
E_STREAMER_Z //(Float) Редактирование/узнавание координаты Z
}
Имейте в виду: Некоторые типы того, что можно изменить у элемента применимы только для определённых типов элементов, а не для всех! К примеру "E_STREAMER_INVULNERABLE" явно намекает на редактирование неуязвимости для актёра, и вряд ли возымеет эффект, если вы попытаетесь применить её для объекта или мап-иконки.
Функции манипуляции данными
Streamer_(Get/Set)(Int/Float)Data и другие
Собственно, начнём с простого примера. Как было сказано в начале, мы имеем немалое количество функций, которые позволяют производить различные действия над объектами, актёрами, 3D-текстами и прочим, но для которых нет явных стримерских аналогов. Это такие функции, как: GetDynamicObjectModel, AttachDynamic3DTextLabelToPlayer, AttachDynamic3DTextLabelToVehicle и т.д. Что же делать, спросите вы наконец? Как их добавить или хотя-бы сделать то, что они делают, как-то самому, "вручную".
Для этого нам на помощь приходят функции Streamer_GetIntData и Streamer_SetIntData (именно на их примере я и начну рассказ о функциях манипуляции данными).
- Streamer_GetIntData
Как написано в вики, эта функция узнаёт (получает) целочисленные данные стримерского элемента.
PHP код:
Streamer_GetIntData(type, id, data)
Параметры:
type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете узнать у элемента (из enum'а).
Возвращает:
Целочисленное значение данных.
Использование (на примере реализации функции GetDynamicObjectModel):
PHP код:
stock GetDynamicObjectModel(objectid)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали сам ID элемента - objectid
//В третий аргумент тип данных, который хотим узнать - E_STREAMER_MODEL_ID
//По итогу: узнаём и возвращаем модель динамического объекта
return Streamer_GetIntData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_MODEL_ID);
}
- Streamer_SetIntData
По информации с той же вики, эта функция устанавливает целочисленные данные для стримерского элемента.
PHP код:
Streamer_SetIntData(type, id, data, value)
Параметры:
type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
value: Устанавливаемое целое значение.
Возвращает:
0 при неудаче, 1 при успешном выполнении.
Использование (на примере реализации функции SetDynamicObjectModel):
PHP код:
stock SetDynamicObjectModel(objectid, modelid)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали сам ID элемента - objectid
//В третий аргумент тип данных, который хотим установить - E_STREAMER_MODEL_ID
//В четвёртый аргумент сам ID желаемой модели - modelid
//По итогу: задаём модель динамического объекта и возвращаем результат выполнения функции
return Streamer_SetIntData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_MODEL_ID, modelid);
}
Как вы могли заметить, выше в enum'е со всеми перечислениями под комментариями в начале стоят "Int" или "Float" для каждого типа. Так я пометил, что нужно вызывать через Streamer_(Get/Set)IntData, а что через Streamer_(Get/Set)FloatData, чтобы у вас вдруг не возникло путаницы. Далее мы как раз рассмотрим функции Streamer_GetFloatData и Streamer_SetFloatData, которые, по сути, абсолютно аналогичны двум предыдущим, только уже работают с вещественным типом данных (Float).
- Streamer_GetFloatData
Эта функция узнаёт (получает) из стримерского элемента значение типа Float.
PHP код:
Streamer_GetFloatData(type, id, data, &Float:result)
Параметры:
type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете узнать у элемента (из enum'а).
result: Переменная, куда запишется результат.
Возвращает:
0 при неудаче, 1 при успешном выполнении (узнаваемое значение тут уже передаётся в result).
Использование (на примере реализации функции GetDynamicPickupPos):
PHP код:
stock GetDynamicPickupPos(pickupid, &Float:x, &Float:y, &Float:z)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_PICKUP
//Во второй аргумент передали сам ID элемента - pickupid
//В третий аргумент тип данных, который хотим узнать - E_STREAMER_X
//В четвёртый аргумент саму координату x - x
Streamer_GetFloatData(STREAMER_TYPE_PICKUP, pickupid, E_STREAMER_X, x);
//В третий аргумент тип данных, который хотим узнать - E_STREAMER_Y
//В четвёртый аргумент саму координату y - y
Streamer_GetFloatData(STREAMER_TYPE_PICKUP, pickupid, E_STREAMER_Y, y);
//В третий аргумент тип данных, который хотим узнать - E_STREAMER_Z
//В четвёртый аргумент саму координату z - z
//По итогу: узнаём позицию динамического пикапа и возвращаем результат выполнения функции
return Streamer_GetFloatData(STREAMER_TYPE_PICKUP, pickupid, E_STREAMER_Z, z);
}
- Streamer_SetFloatData
Эта функция устанавливает для стримерского элемента значение типа Float.
PHP код:
Streamer_SetFloatData(type, id, data, Float:value)
Параметры:
type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить для элемента (из enum'а).
value: Устанавливаемое значение.
Возвращает:
0 при неудаче, 1 при успешном выполнении.
Использование (на примере реализации функции AttachDynamic3DTextLabelToPlayer и AttachDynamic3DTextLabelToVehicle):
PHP код:
stock AttachDynamic3DTextLabelToPlayer(Text3D:labelid, playerid, Float:offsetx, Float:offsety, Float:offsetz)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_3D_TEXT_LABEL
//Во второй аргумент передали сам ID элемента - labelid
//В третий аргумент тип данных, который хотим установить - E_STREAMER_ATTACHED_PLAYER
//В четвёртый аргумент сам ID игрока - playerid
Streamer_SetIntData(STREAMER_TYPE_3D_TEXT_LABEL, labelid, E_STREAMER_ATTACHED_PLAYER, playerid);
//В третий аргумент тип данных, который хотим установить - E_STREAMER_ATTACH_OFFSET_X
//В четвёртый аргумент саму координату смещения аттача по x - offsetx
Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, labelid, E_STREAMER_ATTACH_OFFSET_X, offsetx);
//В третий аргумент тип данных, который хотим установить - E_STREAMER_ATTACH_OFFSET_Y
//В четвёртый аргумент саму координату смещения аттача по y - offsety
Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, labelid, E_STREAMER_ATTACH_OFFSET_Y, offsety);
//В третий аргумент тип данных, который хотим установить - E_STREAMER_ATTACH_OFFSET_Z
//В четвёртый аргумент саму координату смещения аттача по z - offsetz
//По итогу: аттачим динамический 3D-текст к игроку на заданные координаты и возвращаем результат выполнения функции
return Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, labelid, E_STREAMER_ATTACH_OFFSET_Z, offsetz);
}
stock AttachDynamic3DTextLabelToVehicle(Text3D:labelid, vehicleid, Float:offsetx, Float:offsety, Float:offsetz)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_3D_TEXT_LABEL
//Во второй аргумент передали сам ID элемента - labelid
//В третий аргумент тип данных, который хотим установить - E_STREAMER_ATTACHED_VEHICLE
//В четвёртый аргумент сам ID машины - vehicleid
Streamer_SetIntData(STREAMER_TYPE_3D_TEXT_LABEL, labelid, E_STREAMER_ATTACHED_VEHICLE, vehicleid);
//В третий аргумент тип данных, который хотим установить - E_STREAMER_ATTACH_OFFSET_X
//В четвёртый аргумент саму координату смещения аттача по x - offsetx
Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, labelid, E_STREAMER_ATTACH_OFFSET_X, offsetx);
//В третий аргумент тип данных, который хотим установить - E_STREAMER_ATTACH_OFFSET_Y
//В четвёртый аргумент саму координату смещения аттача по y - offsety
Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, labelid, E_STREAMER_ATTACH_OFFSET_Y, offsety);
//В третий аргумент тип данных, который хотим установить - E_STREAMER_ATTACH_OFFSET_Z
//В четвёртый аргумент саму координату смещения аттача по z - offsetz
//По итогу: аттачим динамический 3D-текст к машине на заданные координаты и возвращаем результат выполнения функции
return Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, labelid, E_STREAMER_ATTACH_OFFSET_Z, offsetz);
}
Хорошо, с этим разобрались. И как вы, наверное, снова могли заметить, в enum'е некоторые типы данных под комментариями также имеют пометку в скобках "Array", что означает, что в эти типы могут записывать/узнавать данные в качестве массива, а не отдельной единичной переменной. Рассмотрим простой практический пример: на этот раз нам нужно установить для объекта три интерьера (а именно 2, 3 и 5), в которых он будет виден игрокам. Напомню, что такое возможно сделать, к примеру, при его создании через CreateDynamicObjectEx, но нам нужно проделать это с уже созданным объектом. И о какая удача, что тип данных для установки "E_STREAMER_INTERIOR_ID" как раз имеет пометку Array! (на самом деле это просто я заранее выбрал подходящий для примера тип, не обольщайтесь).
Ок, как же нам сделать это через массив (а любые данные вроде нескольких интерьеров или чего-либо ещё придётся всегда передавать именно через него), если функции выше работают только с одиночными переменными? Для этого нам понадобятся функции Streamer_GetArrayData и Streamer_SetArrayData, встречайте.
- Streamer_GetArrayData
Эта функция узнаёт (получает) данные в качестве массива у стримерского элемента.
PHP код:
Streamer_GetArrayData(type, id, data, dest[], maxdest = sizeof dest)
Параметры:
type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете узнать у элемента (из enum'а).
dest: Массив, в который запишется результат.
maxdest: Размер массива с данными (по умолчанию размер dest).
Возвращает:
0 при неудаче, 1 при успешном выполнении (узнаваемый массив значений передаётся в dest).
Использование (на примере реализации функции GetDynamicObjectInteriors):
PHP код:
stock GetDynamicObjectInteriors(objectid, interiors[], maxinteriors = sizeof interiors)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали сам ID элемента - objectid
//В третий аргумент тип данных, который хотим узнать - E_STREAMER_INTERIOR_ID
//В четвёртый аргумент сам массив interiors - interiors
//В пятый аргумент размер массива interiors - maxinteriors
//По итогу: узнаём все интерьеры (если он не 1), в которых отображается динамический объект и возвращаем результат выполнения функции
return Streamer_GetArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_INTERIOR_ID, interiors, maxinteriors);
}
//Использование получившейся функции в коде
new interiors[5]; //Таким образом в этот массив сможет записаться максимум 5 первых интерьеров, если вдруг объект имеет больше
GetDynamicObjectInteriors(objectid, interiors, sizeof interiors); //Если объект отображается во 2, 3 и 5 интерьерах, то interiors = {2, 3, 5}
- Streamer_SetArrayData
Эта функция устанавливает данные в качестве массива для стримерского элемента.
PHP код:
Streamer_SetArrayData(type, id, data, dest[], maxdest = sizeof dest)
Параметры:
type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
dest: Массив с данными для установки.
maxdest: Размер массива с данными (по умолчанию размер dest).
Возвращает:
0 при неудаче, 1 при успешном выполнении.
Использование (на примере реализации функции SetDynamicObjectInteriors):
PHP код:
stock SetDynamicObjectInteriors(objectid, interiors[], maxinteriors = sizeof interiors)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали сам ID элемента - objectid
//В третий аргумент тип данных, который хотим установить - E_STREAMER_INTERIOR_ID
//В четвёртый аргумент сам массив interiors - interiors
//В пятый аргумент размер массива interiors - maxinteriors
//По итогу: устанавливаем несколько интерьеров, в которых будет отображаться динамический объект и возвращаем результат выполнения функции
return Streamer_SetArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_INTERIOR_ID, interiors, maxinteriors);
}
//Использование получившейся функции в коде
new interiors[] = {2, 3, 5}; //Таким образом в этом массиве записаны 3 интерьера: интерьер 2, 3 и 5
SetDynamicObjectInteriors(objectid, interiors, sizeof interiors); //Теперь объект будет отображаться только в интерьерах 2, 3 и 5
Ура! Уже более-менее умеем узнавать и изменять данные у стримерских элементов, но для работы с массивами есть ещё пара функций... Зачем здесь что-то ещё, спросите вы? Но вы ведь заметили, что в примере выше, устанавливая несколько интерьеров нашему объекту, мы абсолютно не учитываем, в каких интерьерах он отображался до нашего вмешательства и тупо перезаписываем всё на наши значения. Согласитесь, что было бы удобно как-то добавлять в этот массив данные, не вызывая сначала их узнавание, записывание в буферный массив, объединение с новыми данными, и уже только потом их установка этому элементу. А ещё представьте обратную ситуацию: объект уже отображается во множестве интерьеров, но нам нужно один или два интерьера из этого списка удалить. Схема ваших действий, если бы вы жили в параллельной реальности, где других функций больше бы не было, была бы примерно такой же, как и в предыдущем варианте. Но, к счастью, мы живём именно в той, где Incognito добавил для таких случаев функции Streamer_AppendArrayData и Streamer_RemoveArrayData.
- Streamer_AppendArrayData
Эта функция добавляет данные (одно значение) в массив для стримерского элемента.
PHP код:
Streamer_AppendArrayData(type, id, data, value)
Параметры:
type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
value: Значение для добавления в массив.
Возвращает:
0 при неудаче, 1 при успешном выполнении.
Использование (на примере реализации функции AddDynamicObjectInterior):
PHP код:
stock AddDynamicObjectInterior(objectid, interiorid)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали сам ID элемента - objectid
//В третий аргумент тип данных, который хотим установить - E_STREAMER_INTERIOR_ID
//В четвёртый аргумент сам интерьер - interiorid
//По итогу: добавляем интерьер к уже имеющимся, в которых будет отображаться динамический объект и возвращаем результат выполнения функции
return Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_INTERIOR_ID, interiorid);
}
- Streamer_RemoveArrayData
Эта функция удаляет данные (одно значение) из массива для стримерского элемента.
PHP код:
Streamer_RemoveArrayData(type, id, data, value)
Параметры:
type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
value: Значение для удаления из массива.
Возвращает:
0 при неудаче, 1 при успешном выполнении.
Использование (на примере реализации функции RemoveDynamicObjectInterior):
PHP код:
stock RemoveDynamicObjectInterior(objectid, interiorid)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали сам ID элемента - objectid
//В третий аргумент тип данных, который хотим установить - E_STREAMER_INTERIOR_ID
//В четвёртый аргумент сам интерьер - interiorid
//По итогу: удаляем интерьер из списка уже имеющихся, в которых будет отображаться динамический объект и возвращаем результат выполнения функции
return Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_INTERIOR_ID, interiorid);
}
Также мы можем в любой момент проверить, есть ли конкретное значение в этом массиве данных или нет. За примером "для чего это", опять же, далеко ходить не надо: предположим, нам нужно узнать, отображается ли объект в конкретном интерьере, но при этом мы знаем, что он отображается в нескольких и мы не хотим получать для этого весь их список и уже поочерёдно сверять циклом все его значения с тем интерьером, который мы захотели проверить. Мы просто хотим сделать это одной функцией, и такая функция тоже есть - Streamer_IsInArrayData.
- Streamer_IsInArrayData
Эта функция узнаёт: есть ли указанное значение в массиве у стримерского элемента.
PHP код:
Streamer_IsInArrayData(type, id, data, value)
Параметры:
type: Тип элемента.
id: ID элемента.
data: Тип данных, в массиве которого будет идти поиск (тип из enum'а).
value: Значение для поиска в массиве.
Возвращает:
0, если значение в массиве не найдено и 1, если найдено.
Использование (на примере реализации функции IsDynamicObjectInInterior):
PHP код:
stock IsDynamicObjectInInterior(objectid, interiorid)
{
if(interiorid == -1) return 1; //Если пользователь указал аргумент "interiorid" как -1, возвращаем 1 (-1 обозначается стримером как все интерьеры, соответственно будем считать это правдой, потому как объект очевидно в каком-то из всех интерьеров)
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали сам ID элемента - objectid
//В третий аргумент тип данных, который хотим узнать - E_STREAMER_INTERIOR_ID
if(Streamer_GetIntData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_INTERIOR_ID) == -1) return 1; //Если объекту задан -1 интерьер, возвращаем 1 по той же причине
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали сам ID элемента - objectid
//В третий аргумент тип данных, который хотим узнать - E_STREAMER_INTERIOR_ID
//В четвёртый аргумент сам интерьер - interiorid
//По итогу: узнаём, отображается ли динамический объект в указанном интерьере и возвращаем результат выполнения функции
return Streamer_IsInArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_INTERIOR_ID, interiorid);
}
//Использование получившейся функции (в связке с уже добавленной SetDynamicObjectInteriors) в коде
new interiors[] = {2, 3, 5}; //Таким образом в этом массиве записаны 3 интерьера: интерьер 2, 3 и 5
SetDynamicObjectInteriors(objectid, interiors, sizeof interiors); //Теперь объект будет отображаться только в интерьерах 2, 3 и 5
IsDynamicObjectInInterior(objectid, 2); //Результат - 1 (объект находится в интерьере 2)
IsDynamicObjectInInterior(objectid, 3); //Результат - 1 (объект находится в интерьере 3)
IsDynamicObjectInInterior(objectid, 6); //Результат - 0 (объект не находится в интерьере 6)
Назревает последний вопрос при работе с данными в массивах: а как узнать длину уже имеющегося массива с заполненными данными для конкретного стримерского элемента, если мы хотим, к примеру, узнать общее количество данных в нём (а длина массива как раз говорит о том, сколько ячеек там занято, и, соответственно, число данных в массиве). И на это существует функция с названием Streamer_GetArrayDataLength, о которой сейчас и будет чуть подробнее.
- Streamer_GetArrayDataLength
Эта функция узнаёт длину массива данных для указанного стримерского элемента.
PHP код:
Streamer_GetArrayDataLength(type, id, data)
Параметры:
type: Тип элемента.
id: ID элемента.
data: Тип данных, длина массива которого будет узнана (тип из enum'а).
Возвращает:
Длину массива данных.
Примечание:
Использование (на примере реализации функции GetDynamicObjectInteriorsCount):
PHP код:
stock GetDynamicObjectInteriorsCount(objectid)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали сам ID элемента - objectid
//В третий аргумент тип данных, который хотим узнать - E_STREAMER_INTERIOR_ID
//По итогу: узнаём и возвращаем количество интерьеров, в которых отображается динамический объект
return Streamer_GetArrayDataLength(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_INTERIOR_ID);
}
Примечание ко всем примерам с интерьерами выше: важно также отметить, что, как написано в официальной вики стримера, установка стримерскому элементу множества интерьеров или виртуальных миров может снизить производительность стримера. Идеальным вариантом, если вы хотите, чтобы элемент отображался везде, будет значение '-1'. Добавление множества интерьеров было лишь примерами, что это сделать возможно.
Ну и наконец, добивая этот раздел (и первую часть этого урока), остаётся представить ещё одну функцию, которая является аналогом функциям GetPlayerPoolSize/GetVehiclePoolSize, то есть по сути она узнаёт и возвращает наивысший занятый ид любого элемента, созданного стримером. Это функция Streamer_GetUpperBound. Может быть полезна в циклах в качестве использования как наивысшее значение, до которого он будет выполняться. Важным моментом является то, что наивысший ID созданного элемента не всегда отражает реальное количество всех созданных элементов вообще (для этого есть другая функция, о которой будет рассказано чуть позже), потому что если мы, к примеру, по порядку создадим стримерские объекты с идами 1, 2, 3, 4, 5, а потом удалим 3 и 4, то функция Streamer_GetUpperBound будет возвращать 5 как наивысший занятый ид для стримерских объектов, хотя всех созданных объектов уже будет 3 (с идами 1, 2, 5).
Заключение
Думаю, уже по ознакомлению с первой частью вам стало видно, что стример обладает поистине богатым функционалом, с помощью которого можно делать абсолютно любые вещи над стримерскими элементами, в числе которых и те, что для обычных объектов/актёров/пикапов/map-иконок или 3D-текстов просто недоступны в сампе нативно. Это даёт большое преимущество в использовании стримера не только тогда, когда нужно просто расширить лимиты, но и эффективно управлять всем через него созданным, что теперь, я надеюсь, вы и умеете делать. Однако есть ещё как минимум два раздела, которые мы не рассмотрели и обязательно сделаем это в следующих частях: на очереди у нас функции настройки элементов стримера (Streamer_SetMaxItems, Streamer_SetVisibleItems, Streamer_GetTypePriority и т.д.) и раздел "Разное" (Streamer_GetDistanceToItem, Streamer_GetItemStreamerID, Streamer_CountItems и т.д.).
Домашнее задание
Ну а пока готовится вторая часть, предлагаю вам сделать некоторые задания, которые помогут вам убедиться, что вы точно теперь понимаете, как с этим работать. Первые посты с правильной реализацией каждого задания (не противоречащей любому из условий) пролайкаю :grin:
- Написать функцию, которая будет возвращать ID модели динамического пикапа.
Примерный шаблон функции: GetDynPickupModel(pickupid);
Должна возвращать: модель стримерского пикапа. - Написать функцию, которая будет устанавливать дальность прорисовки (DrawDistance) для динамического объекта без его пересоздания.
Примерный шаблон функции: SetDynObjectDrawDistance(objectid, Float:drawdist);
Должна возвращать: 1 в случае успешного выполнения и 0 в случае неудачи. - Написать функцию, которая будет вычислять: создан ли стримером 3D-текст для конкретного указанного игрока. Заметьте, что узнать нужно именно факт существования динамического 3D-текста для игрока (а не его видимость в данный момент или что-то ещё).
Примерный шаблон функции: IsDyn3DTextLabelExistForPlayer(labelid, playerid);
Должна возвращать: 1, если стримерский 3D-текст создан для этого игрока и 0, если не создан.
Ссылки по теме
Streamer Plugin
Streamer Functions include
Streamer Plugin Wiki