PDA

Просмотр полной версии : [Урок] Дополнительные функции стримера / Функции манипуляции данными [Часть 1]



Nexius_Tailer
07.02.2018, 01:17
Вторая часть: перейти (https://pro-pawn.ru/showthread.php?16078).
Третья часть: перейти (https://pro-pawn.ru/showthread.php?16854).


Дисклеймер

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

Предисловие

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

Кстати, если вы здесь именно поэтому, то есть нуждаетесь в каком-либо функционале, коего вы не можете найти в стримере в качестве отдельных выделенных функций, то могу порекомендовать очень полезный include Streamer Functions (кликабельно) (https://pro-pawn.ru/showthread.php?17337-StreamerFunction), в котором есть абсолютно всё что вам нужно, и который, собственно, стал поводом для написания данной статьи.

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

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

Определения (макросы)
для стримерских элементов

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

Список чего-либо виден ниже:

#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, перечисляющий все данные, которые могут быть установлены большинством второстепенных функций стримера:

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

Как написано в вики, эта функция узнаёт (получает) целочисленные данные стримерского элемента.


Streamer_GetIntData(type, id, data)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете узнать у элемента (из enum'а).

Возвращает:

Целочисленное значение данных.

Использование (на примере реализации функции GetDynamicObjectModel):

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

По информации с той же вики, эта функция устанавливает целочисленные данные для стримерского элемента.


Streamer_SetIntData(type, id, data, value)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
value: Устанавливаемое целое значение.

Возвращает:

0 при неудаче, 1 при успешном выполнении.

Использование (на примере реализации функции SetDynamicObjectModel):

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.


Streamer_GetFloatData(type, id, data, &Float:result)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете узнать у элемента (из enum'а).
result: Переменная, куда запишется результат.

Возвращает:

0 при неудаче, 1 при успешном выполнении (узнаваемое значение тут уже передаётся в result).

Использование (на примере реализации функции GetDynamicPickupPos):

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.


Streamer_SetFloatData(type, id, data, Float:value)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить для элемента (из enum'а).
value: Устанавливаемое значение.

Возвращает:

0 при неудаче, 1 при успешном выполнении.

Использование (на примере реализации функции AttachDynamic3DTextLabelToPlayer и AttachDynamic3DTextLabelToVehicle):

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

Эта функция узнаёт (получает) данные в качестве массива у стримерского элемента.


Streamer_GetArrayData(type, id, data, dest[], maxdest = sizeof dest)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете узнать у элемента (из enum'а).
dest: Массив, в который запишется результат.
maxdest: Размер массива с данными (по умолчанию размер dest).

Возвращает:

0 при неудаче, 1 при успешном выполнении (узнаваемый массив значений передаётся в dest).

Использование (на примере реализации функции GetDynamicObjectInteriors):

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

Эта функция устанавливает данные в качестве массива для стримерского элемента.


Streamer_SetArrayData(type, id, data, dest[], maxdest = sizeof dest)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
dest: Массив с данными для установки.
maxdest: Размер массива с данными (по умолчанию размер dest).

Возвращает:

0 при неудаче, 1 при успешном выполнении.

Использование (на примере реализации функции SetDynamicObjectInteriors):

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

Эта функция добавляет данные (одно значение) в массив для стримерского элемента.


Streamer_AppendArrayData(type, id, data, value)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
value: Значение для добавления в массив.

Возвращает:

0 при неудаче, 1 при успешном выполнении.

Использование (на примере реализации функции AddDynamicObjectInterior):

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

Эта функция удаляет данные (одно значение) из массива для стримерского элемента.


Streamer_RemoveArrayData(type, id, data, value)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
value: Значение для удаления из массива.

Возвращает:

0 при неудаче, 1 при успешном выполнении.

Использование (на примере реализации функции RemoveDynamicObjectInterior):

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

Эта функция узнаёт: есть ли указанное значение в массиве у стримерского элемента.


Streamer_IsInArrayData(type, id, data, value)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, в массиве которого будет идти поиск (тип из enum'а).
value: Значение для поиска в массиве.

Возвращает:

0, если значение в массиве не найдено и 1, если найдено.

Использование (на примере реализации функции IsDynamicObjectInInterior):

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

Эта функция узнаёт длину массива данных для указанного стримерского элемента.


Streamer_GetArrayDataLength(type, id, data)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, длина массива которого будет узнана (тип из enum'а).

Возвращает:

Длину массива данных.

Примечание:

Эта функция появилась лишь совсем недавно в версии 2.9.3, для её использования вам следует обновить стример (кликабельно) (https://github.com/samp-incognito/samp-streamer-plugin/releases).

Использование (на примере реализации функции GetDynamicObjectInteriorsCount):

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).

Streamer_GetUpperBound

Эта функция узнаёт наивысший занятый ID для указанного типа стримерских элементов.


Streamer_GetUpperBound(type)
Параметры:

type: Тип элемента.

Возвращает:

Наивысший занятый ID.

Использование (на примере реализации функции StopAllDynamicObjects):

stock StopAllDynamicObjects()
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//По итогу: узнаём наивысший занятый ID динамического объекта
for(new i = 1, j = Streamer_GetUpperBound(STREAMER_TYPE_OBJECT); i <= j; i++) //Объекты стартуют с ида 1 (отсюда i = 1)
{
StopDynamicObject(i); //Останавливаем (возможно) движущийся динамический объект
}
return 1;
}

Заключение

Думаю, уже по ознакомлению с первой частью вам стало видно, что стример обладает поистине богатым функционалом, с помощью которого можно делать абсолютно любые вещи над стримерскими элементами, в числе которых и те, что для обычных объектов/актёров/пикапов/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 (https://github.com/samp-incognito/samp-streamer-plugin)
Streamer Functions include (https://pro-pawn.ru/showthread.php?17337-StreamerFunction)
Streamer Plugin Wiki (https://github.com/samp-incognito/samp-streamer-plugin/wiki)

DeimoS
07.02.2018, 08:13
С оформлением бы поработать. А именно как-то выделить имена функций, к которым в последующем идёт описание. Сейчас они и по размеру текста, и по цвету совпадают с пунктами описания, что выглядит не очень (особенно когда нужно будет найти тот или иной пункт через некоторое время после прочтения статьи, дабы освежить память).

Можно хотя бы с отступами поиграться как-нибудь так:



Streamer_GetArrayData

Эта функция узнаёт (получает) данные в качестве массива у стримерского элемента:


Streamer_GetArrayData(type, id, data, dest[], maxdest = sizeof dest)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете узнать у элемента (из enum'а).
dest: Массив, в который запишется результат.
maxdest: Размер массива с данными (по умолчанию размер dest).

Возвращает:

0 при неудаче, 1 при успешном выполнении (узнаваемый массив значений передаётся в dest).

Использование (на примере реализации функции GetDynamicObjectInteriors):


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

Эта функция устанавливает данные в качестве массива для стримерского элемента:


Streamer_SetArrayData(type, id, data, dest[], maxdest = sizeof dest)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
dest: Массив с данными для установки.
maxdest: Размер массива с данными (по умолчанию размер dest).

Возвращает:

0 при неудаче, 1 при успешном выполнении.

Использование (на примере реализации функции SetDynamicObjectInteriors):


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

Эта функция добавляет данные (одно значение) в массив для стримерского элемента:


Streamer_AppendArrayData(type, id, data, value)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
value: Значение для добавления в массив.

Возвращает:

0 при неудаче, 1 при успешном выполнении.

Использование (на примере реализации функции AddDynamicObjectInterior):


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);
}




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

Daniel_Cortez
07.02.2018, 12:53
Тёмно-красный цвет плохо смотрится на тёмном фоне (http://pro-pawn.ru/showthread.php?15934&styleid=18), приходится напрягать глаза, чтобы хоть что-то прочесть. Лично я использую для подзаголовков оранжевый цвет, но в принципе может подойти любой, главное чтобы он смотрелся примерно одинаково и на светлом, и на тёмном фоне.


могу порекомендовать очень полезный include Streamer Functions
Вот здесь не помешало бы указать ссылку.


Эта функция узнаёт (получает) Float данные стримерского элемента
Что за странная мода в словосочетаниях ставить зависимые слова из англ. языка перед главными? Серьёзно, никогда не понимал этого.
Проверяется очень просто: как правильно, "экземпляр объекта" или "объекта экземпляр"? Здесь то же самое, для слов из инглиша исключений нет.


Думаю, эти несколько изменений, и можно смело перемещать статью в проверенные.

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

Nexius_Tailer
07.02.2018, 21:58
С оформлением бы поработать. А именно как-то выделить имена функций, к которым в последующем идёт описание. Сейчас они и по размеру текста, и по цвету совпадают с пунктами описания, что выглядит не очень (особенно когда нужно будет найти тот или иной пункт через некоторое время после прочтения статьи, дабы освежить память).

Можно хотя бы с отступами поиграться как-нибудь так:



Streamer_GetArrayData

Эта функция узнаёт (получает) данные в качестве массива у стримерского элемента:


Streamer_GetArrayData(type, id, data, dest[], maxdest = sizeof dest)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете узнать у элемента (из enum'а).
dest: Массив, в который запишется результат.
maxdest: Размер массива с данными (по умолчанию размер dest).

Возвращает:

0 при неудаче, 1 при успешном выполнении (узнаваемый массив значений передаётся в dest).

Использование (на примере реализации функции GetDynamicObjectInteriors):


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

Эта функция устанавливает данные в качестве массива для стримерского элемента:


Streamer_SetArrayData(type, id, data, dest[], maxdest = sizeof dest)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
dest: Массив с данными для установки.
maxdest: Размер массива с данными (по умолчанию размер dest).

Возвращает:

0 при неудаче, 1 при успешном выполнении.

Использование (на примере реализации функции SetDynamicObjectInteriors):


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

Эта функция добавляет данные (одно значение) в массив для стримерского элемента:


Streamer_AppendArrayData(type, id, data, value)
Параметры:

type: Тип элемента.
id: ID элемента.
data: Тип данных, кои желаете установить элементу (из enum'а).
value: Значение для добавления в массив.

Возвращает:

0 при неудаче, 1 при успешном выполнении.

Использование (на примере реализации функции AddDynamicObjectInterior):


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);
}




Хотя в идеале ещё играться с цветом/размером букв, ибо в таких объёмных статьях трудно воспринимать информацию, когда она чуть ли не сплошным текстом написана
Про отступ и размер текста возьму на заметку, но вот выравнивание сплошного текста по центру как по мне выглядит не всегда в тему и читается не очень.


Тёмно-красный цвет плохо смотрится на тёмном фоне (http://pro-pawn.ru/showthread.php?15934&styleid=18), приходится напрягать глаза, чтобы хоть что-то прочесть. Лично я использую для подзаголовков оранжевый цвет, но в принципе может подойти любой, главное чтобы он смотрелся примерно одинаково и на светлом, и на тёмном фоне.
На тёмном фоне и код в php смотрится не очень, но всех вроде устраивает)
Раньше экспериментировал с разными более яркими цветами, на белом фоне тоже не всегда всё хорошо среди них воспринималось. В этот раз не особо заморачивался, но думаю на белой теме вполне нормальный вариант.


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


Что за странная мода в словосочетаниях ставить зависимые слова из англ. языка перед главными? Серьёзно, никогда не понимал этого.
Проверяется очень просто: как правильно, "экземпляр объекта" или "объекта экземпляр"? Здесь то же самое, для слов из инглиша исключений нет.
Мне так больше нравится и смотрится, как мне кажется, это понятнее. "Данные Float стримерского объекта" сложнее воспринять, т.к. в таком случае это больше походит на набор слов, нежели на какое-то предложение, имеющее смысл, приходится перечитывать. Нет никакой нужды в этом случае что-то соблюдать (если и есть в этом нормы), когда в конечном итоге это только всё усложнит для конечного пользователя, которому, уверен, это также малоинтересно.


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

VVWVV
07.02.2018, 22:12
Изначально указывал, но потом вспомнил, что совсем недавно его автора забанили на офе и большинство работ он, к сожалению, удалил (включая эту) и в конечном итоге её убрал, чтобы было меньше вопросов. В конце оставил на неё ссылку лишь для ознакомления, возможно когда-нибудь кто-нибудь перезальёт.

У него же другой аккаунт есть. вот (https://github.com/Calzaghe/SAMP/)

Nexius_Tailer
07.02.2018, 22:14
У него же другой аккаунт есть. вот (https://github.com/Calzaghe/SAMP/)
О, спасибо. Теперь можно и добавить)

Upd:
Немного обновил тему: добавлена ссылка на сам исходный код инклуда Streamer Functions, а также теперь немного лучше выделены заголовки функций для их более удобного поиска в сообщении.

DeimoS
08.02.2018, 07:05
но вот выравнивание сплошного текста по центру как по мне выглядит не всегда в тему и читается не очень.

Ну это просто была попытка как-то большой однородный кусок текста выделить, отделив от описания функций. Это можно и чуть изменённым шрифтом сделать, найдя похожий на основной шрифт. Или чертами сверху и снизу через BB код [HR ][ /HR]

Daniel_Cortez
08.02.2018, 12:31
На тёмном фоне и код в php смотрится не очень, но всех вроде устраивает)
Вот только не надо переводить стрелки на форум. Подсветка PHP-кода, в том числе и цвет фона, захардкожена в коде форумного движка и никак не настраивается. Если же менять цвета в коде, они сменятся и на светлой форумной теме, и на тёмной.


В этот раз не особо заморачивался, но думаю на белой теме вполне нормальный вариант.
Это не устраняет проблему с тёмным фоном. В общем, звучит, как очередное
http://ihost.pro-pawn.ru/image.php?di=OVP6


"Данные Float стримерского объекта" сложнее воспринять
Ну так это ж далеко не единственный вариант. Если подумать, можно получить что-то вроде:

Эта функция узнаёт (получает) из стримерского элемента значение типа Float:
Собственно, так я и сделал ещё вчера, когда правил пунктуацию и грамматику. Хотя пока что складывается ощущение, что не стоило даже и пытаться.

Nexius_Tailer
08.02.2018, 13:34
Ну это просто была попытка как-то большой однородный кусок текста выделить, отделив от описания функций. Это можно и чуть изменённым шрифтом сделать, найдя похожий на основной шрифт. Или чертами сверху и снизу через BB код [HR ][ /HR]
В целом с добавлением пунктов для функций ситуация уже вроде лучше, сейчас можно легко сориентироваться по точкам перед ними (за что, кстати, спасибо, довольно интересная идея для оформления как оказывается). Шрифт и всё остальное, я думаю, лучше оставить для единого стиля.


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


Это не устраняет проблему с тёмным фоном. В общем, звучит, как очередное
http://ihost.pro-pawn.ru/image.php?di=OVP6
Это выглядит как очередное удобство для большинства, кто сидит но белой теме, ибо те, кто ставит себе что-то более экзотическое, должны понимать, что это также для них может нести.


Ну так это ж далеко не единственный вариант. Если подумать, можно получить что-то вроде:
Да, я потом уже это заметил, просто в контексте моей изначальной формулировки то был самый понятный вариант.


Хотя пока что складывается ощущение, что не стоило даже и пытаться.
Не знаю почему складывается, но раз не стоило, нужно было было думать об этом тогда.

Daniel_Cortez
08.02.2018, 14:27
Тут имелось в виду, что пока существуют и более серьёзные неудобства на тёмной теме (неважно чем вызванные, сам факт они есть), напряжение глаз на темноватый цвет это, наверное, самое меньшее из того, что чувствуют его пользователи.
Существуют, только это не повод наплевательски относиться к своему оформлению. Особенно, когда исправить проблему не так уж и сложно.



Это выглядит как очередное удобство для большинства, кто сидит но белой теме, ибо те, кто ставит себе что-то более экзотическое, должны понимать, что это также для них может нести.
"Экзотическое"? Это всегда была обычная форумная тема, наравне со светлой.
Ок, уже понятно, что этот разговор абсолютно ни к каким изменениям не приведёт, но я просто очень хочу знать, разве я прошу что-то сложное?
Работы буквально на пару минут: подобрать цвет чуть посветлее (чтобы смотрелся одинаково удобно и на светлом, и на тёмном фоне) и пройтись по тексту автозаменой. Но нет, нужно упереться и оправдываться в стиле "пользователи сами виноваты". Странная логика. Многое говорит об отношении и к своему контенту, и к читателям.

Nexius_Tailer
08.02.2018, 20:16
Работы буквально на пару минут: подобрать цвет чуть посветлее (чтобы смотрелся одинаково удобно и на светлом, и на тёмном фоне) и пройтись по тексту автозаменой. Но нет, нужно упереться и оправдываться в стиле "пользователи сами виноваты". Странная логика. Многое говорит об отношении и к своему контенту, и к читателям.
Это преувеличение и скорее раздувание из мухи слона. Мне изначально хотелось красный, но в силу его яркости на белом фоне этот цвет был более адекватным и менее броским. Собственно, искать какие-то там компромиссы для трёх с половиной человек с тёмной темой у меня просто нет желания. И не стоит "переводить стрелки" на отношение к контенту и читателям, если конкретно ты считаешь иначе и по твоему это настолько важно, чтобы начать с этого дискуссию.

Daniel_Cortez
08.02.2018, 22:35
Это преувеличение и скорее раздувание из мухи слона. Мне изначально хотелось красный, но в силу его яркости на белом фоне этот цвет был более адекватным и менее броским. Собственно, искать какие-то там компромиссы для трёх с половиной человек с тёмной темой у меня просто нет желания. И не стоит "переводить стрелки" на отношение к контенту и читателям, если конкретно ты считаешь иначе и по твоему это настолько важно, чтобы начать с этого дискуссию.
Переводом стрелок была твоя попытка перевести тему на цвета в [php]. Можешь и дальше сколько угодно называть это преувеличением, своё упорное нежелание идти на компромиссы - даже ради таких мелочей - ты уже показал.

По поводу дискуссии - да, я указал на необходимость изменения, ведь это требование прописано в правилах раздела (http://pro-pawn.ru/showthread.php?10350), которые существуют не просто так.

9. При окрашивании текста учитывайте то, как он будет выглядеть и на светлом стиле форума, и на тёмном.
Избегайте слишком ярких и слишком тёмных цветов, которые будет сложно различить на светлом/тёмном фоне.
Откуда мне было знать, что ты так будешь упираться из-за простой правки? Хотя да, стоило догадаться, учитывая прошлый опыт (взять те же дискуссии в чате на 10+ страниц с твоим участием, которые, как правило, ни к чему не приводили).

Nexius_Tailer
09.02.2018, 00:16
Переводом стрелок была твоя попытка перевести тему на цвета в [php]. Можешь и дальше сколько угодно называть это преувеличением, своё упорное нежелание идти на компромиссы - даже ради таких мелочей - ты уже показал.
Какой же это перевод стрелок? Это очень толстый намёк на то, что имея такие серьёзные в нём косяки как тот же php (хотя не знаю, может их там ещё больше помимо этого, не особо им пользовался), которые реально доставляют неудобства чтения почти любых тем при его использовании, при этом авторам навязывается соблюдение некой приемлемой цветовой гаммы под этот очевидно изначально недоработанный стиль форума - это как минимум странно. Собственно, отсюда и нежелание идти на такие компромиссы, когда сама администрация форума говорит о серьёзных недоработках (на деле абсолютно второстепенного, но по её мнению несомненно важного) стиля форума как об абсолютной норме и обычных вещах. Какой смысл заставлять пользователей что-то под него подгонять, когда сам стиль выглядит неадаптированным? Какие в этом перспективы? Так что да, как ты выразился, это слишком сомнительная мелочь, чтобы ради такого (особенно ради такого) идти на компромиссы.


По поводу дискуссии - да, я указал на необходимость изменения, ведь это требование прописано в правилах раздела (http://pro-pawn.ru/showthread.php?10350), которые существуют не просто так.
Ну я уже понял, существует для нескольких человек, у которых на этот счёт своя радикальная позиция. Вот только почему она должна разделяться всеми на уровне правил форума - загадка.


Откуда мне было знать, что ты так будешь упираться из-за простой правки? Хотя да, стоило догадаться, учитывая прошлый опыт (взять те же дискуссии в чате на 10+ страниц с твоим участием, которые, как правило, ни к чему не приводили).
Ну в общем-то все причины выше. А насчёт прошлых дискуссий - ни к чему не приводили в первую очередь из-за самих тем дискуссий либо из-за собеседников, очевидно по-моему.

Daniel_Cortez
09.02.2018, 13:43
Ну я уже понял, существует для нескольких человек, у которых на этот счёт своя радикальная позиция. Вот только почему она должна разделяться всеми на уровне правил форума - загадка.

Я уже говорил это ранее и скажу сейчас: основной упор форума идёт на качество контента. В чате это обсуждалось, и не раз, в том числе и с тобой.


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



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

Как я уже говорил ранее, это проблема не стиля, а самого движка (нет средств для настройки цветов в [php], хардкод), и если заменить цвета в коде, они изменятся для обоих стилей. Так что всё отнюдь не так просто, как ты пытаешься это выставить.
Впрочем, если кто-то знает более адекватное решение данной проблемы (повторюсь, решение, а не трёп вида "а на таком-то форуме это же как-то сделали!") - всегда рад выслушать.

Nexius_Tailer
09.02.2018, 14:07
Я уже говорил это ранее и скажу сейчас: основной упор форума идёт на качество контента. В чате это обсуждалось, и не раз, в том числе и с тобой.
Это даже уже смешно. За это обсуждение ни разу о самом контенте, в частности, о правильности/неправильности каких-то утверждений из текста урока речи в принципе и не было. Всё сводится лишь к цвету оформления, и закрепление этой прихоти в правилах форума лишь показывает их абсурдность. Собственно, изначально у меня никаких целей на этот счёт не было, но сейчас я вижу, что на этом примере этот факт был очень хорошо продемонстрирован.


Как я уже говорил ранее, это проблема не стиля, а самого движка (нет средств для настройки цветов в [php], хардкод), и если заменить цвета в коде, они изменятся для обоих стилей. Так что всё отнюдь не так просто, как ты пытаешься это выставить.
Впрочем, если кто-то знает более адекватное решение данной проблемы (повторюсь, решение, а не трёп вида "а на таком-то форуме это же как-то сделали!") - всегда рад выслушать.
Я понимаю, но как это меняет ситуацию и есть ли кому-то до этого дело? Речь идёт даже не о его доработке, а пересмотре самих желаний администрации на этот счёт по отношению к контенту, который обязательно должен иметь адаптацию под то, что само по себе для юзабельного вида не адаптировано.

Nexius_Tailer
26.03.2018, 00:23
Опубликована вторая часть (клик (http://pro-pawn.ru/showthread.php?16078)).

DeimoS
05.01.2020, 19:07
Nexius_Tailer, ты ещё не созрел для того, чтоб прислушаться к тому замечанию, что было озвучено выше? Если сделаешь цвет заголовков удобочитаемым для обоих форумных стилей - перенесу статьи в раздел одобренных тем.
P.S. К слову о твоих претензиях: вместо BB-кода "[php]" появился "[pawn]", который сейчас и на тёмном, и на светлом стиле читается нормально. Хотя, если честно, не совсем понимаю чем тебя не устраивает "[php]" (сколько сижу с тёмным оформлением - никогда "[php]" не создавал проблем для чтения), но не будем об этом.

Nexius_Tailer
05.01.2020, 19:30
Nexius_Tailer, ты ещё не созрел для того, чтоб прислушаться к тому замечанию, что было озвучено выше? Если сделаешь цвет заголовков удобочитаемым для обоих форумных стилей - перенесу статьи в раздел одобренных тем.
Вопрос о "созрел" не ко мне, а скорее к недоработанной тёмной теме форума, которая, насколько помню, была абсолютно сырой и непригодной для использования (собственно, именно поэтому не считал нужным и адаптировать что-то под неё).


P.S. К слову о твоих претензиях: вместо BB-кода "[php]" появился "[pawn]", который сейчас и на тёмном, и на светлом стиле читается нормально. Хотя, если честно, не совсем понимаю чем тебя не устраивает "[php]" (сколько сижу с тёмным оформлением - никогда "[php]" не создавал проблем для чтения), но не будем об этом.
Ну как же, с php тегом (edit: и/или с html, что-то из этой оперы) там точно был вырвиглазный белый фон с еле видным кодом в нём. Насчёт pawn тега, посмотрю. Но опять же, насколько помню, не им одним там ощущалось неудобство и недопиленность темы.

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

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

Nexius_Tailer
11.01.2020, 15:15
Предположим, тебе нужно узнать объект (модель), используемую для стримерского пикапа и прямо при чьём-либо подборе её заменить на другую (без пересоздания пикапа) - стример даёт такую возможность именно благодаря этим функциям. Или, например, тебе вообще нужно задать какие-то данные для этого пикапа свои, как бы имея переменную, привязанную к нему. Массив не вариант - глобальных лимитов у стримера нет. А в случае со всеми этими нативами можно сделать даже это. В общем, функции это действительно не для каждого и это описано в первом-втором абзаце каждой из частей, но при серьёзной интеграции стримера и мода они как раз очень кстати.

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

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