PDA

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



Nexius_Tailer
26.03.2018, 00:18
Первая часть: перейти (https://pro-pawn.ru/showthread.php?15934).
Третья часть: перейти (https://pro-pawn.ru/showthread.php?16854).


Дисклеймер

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

Предисловие

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

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

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

Функции настройки
Streamer_(Get/Set)VisibleItems, Streamer_(Get/Set)TypePriority и другие

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

Если вы всё же не очень сильно переборщили с объектами и с дистанцией прорисовки у них изначально всё в порядке, то ситуацию могут спасти функции Streamer_SetVisibleItems и Streamer_GetVisibleItems (вообще именно в данном случае спасает только первая, но мы рассмотрим обе). Собственно, что они делают?

Streamer_GetVisibleItems

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


Streamer_GetVisibleItems(type, playerid = -1)
Параметры:

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

Возвращает:

Максимальное количество одновременно отображаемых видимых элементов.

Использование:

public OnGameModeInit()
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали ID игрока - в данном случае -1 означает, что мы узнаём не для конкретного игрока, а для всех
//По итогу: узнаём и выводим в консоль максимальное количество видимых объектов для всех игроков
printf("Max visible objects: %d", Streamer_GetVisibleItems(STREAMER_TYPE_OBJECT, -1)); //По умолчанию лимит видимых объектов равен 500, что в данном случае и выведет в лог
return 1;
}

Streamer_SetVisibleItems

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


Streamer_SetVisibleItems(type, items, playerid = -1)
Параметры:

type: Тип элемента.
items: Максимальное количество видимых элементов.
playerid: ID игрока (если не указывать, то будет задан лимит для всех).

Возвращает:

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

Стандартные значения:


Объекты: 500;
Пикапы: 4096;
Мап-иконки: 100;
3d-тексты: 1024:
Актёры: 1000.


Максимально возможные значения (ограничиваются лимитами (http://team.sa-mp.com/wiki/Limits) сампа):


Объекты: 1000 (для 0.3.7), 2000 (для 0.3.DL);
Пикапы: 4096;
Мап-иконки: 100;
3d-тексты: 1024:
Актёры: 1000.


Примечание:

Эта функция не может быть использована с чекпоинтами, гоночными чекпоинтами или стримерскими зонами.

Использование:

public OnGameModeInit()
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали максимальное количество видимых элементов - 1000
//В третий аргумент передали ID игрока - в данном случае -1 означает, что мы задаём не для конкретного игрока, а для всех
//По итогу: устанавливаем максимальное количество видимых объектов для всех игроков
Streamer_SetVisibleItems(STREAMER_TYPE_OBJECT, 1000, -1);
return 1;
}

Прекрасно, с задачей мы справились. Теперь наш быдломаппинг с меньшей вероятностью будет пропадать, находясь в зоне стрима.
А теперь давайте представим, что нам нужно, чтобы стример самыми первыми подгружал мап иконки, потом гоночные чекпоинты, потом обычные чекпоинты, потом объекты, актёров, 3d-тексты, и только потом стримерские зоны и пикапы (и именно в таком порядке!). Сделать мы это можем достаточно просто, через функцию Streamer_SetTypePriority. Но т.к. она задаёт порядок подгрузки всех типов сразу, требуя массив с их перечислением друг за другом, то сначала нам нужно этот порядок на всякий случай узнать. А для этого понадобится функция Streamer_GetTypePriority.

Streamer_GetTypePriority

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


Streamer_GetTypePriority(types[], maxtypes = sizeof types)
Параметры:

types: Массив (не строка) со списком ID'ов типов элементов.
maxtypes: Размер массива types (должен быть равным STREAMER_MAX_TYPES).

Возвращает:

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

Использование:

public OnGameModeInit()
{
//Создадим массив для работы с функцией, куда запишется порядок загрузки типов стримерских элементов
new types[STREAMER_MAX_TYPES]; //STREAMER_MAX_TYPES = 8 (типы элементов от 0 до 7)

//В первый аргумент передали наш массив - types
//Во второй аргумент передали размер нашего массива - sizeof types
//По итогу: узнаём и записываем в массив последовательность типов стримерских элементов в порядке их отображения
Streamer_GetTypePriority(types, sizeof types);

//Создадим ещё один массив для последующего вывода названий типов вместо их ID'ов
static const TypeNames[][] =
{
"Objects", //ячейка 0 (STREAMER_TYPE_OBJECT)
"Pickups", //ячейка 1 (STREAMER_TYPE_PICKUP)
"Checkpoints", //ячейка 2 (STREAMER_TYPE_CP)
"Race checkpoints", //ячейка 3 (STREAMER_TYPE_RACE_CP)
"Map icons", //ячейка 4 (STREAMER_TYPE_MAP_ICON)
"3d texts", //ячейка 5 (STREAMER_TYPE_3D_TEXT_LABEL)
"Areas", //ячейка 6 (STREAMER_TYPE_AREA)
"Actors" //ячейка 7 (STREAMER_TYPE_ACTOR)
};

//Выводим результаты в консоль
print("Priority:");
for(new i; i < STREAMER_MAX_TYPES; i++)
{
//Первое значение - номер, каким по счёту грузится тип элементов (начинается с 0, т.е. 0 - самым первым)
//Вторая строка - название типа элементов, под каким номером он грузится
printf("%d. %s", i, TypeNames[types[i]]); //types[i] равно ID'у текущего типа в порядке под номером i, подставляя types[i] как ячейку TypeNames получаем название типа по его иду
}

/*
Если приоритеты заданы по умолчанию, то в результате получим:

Priority:
0. Areas //Сначала грузятся стримерские зоны
1. Objects //Потом объекты
2. Checkpoints //Потом чекпоинты
3. Race checkpoints //Потом гоночные чекпоинты
4. Map icons //Потом мап иконки
5. 3d texts //Потом 3d-тексты
6. Pickups //Потом пикапы
7. Actors //И последними грузятся актёры
*/
return 1;
}

Streamer_SetTypePriority

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


Streamer_SetTypePriority(const types[], maxtypes = sizeof types)
Параметры:

types: Массив (не строка) со списком ID'ов типов элементов.
maxtypes: Размер массива types (должен быть равным STREAMER_MAX_TYPES).

Возвращает:

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

Порядок подгрузки типов элементов по умолчанию:

Стримерские зоны, объекты, чекпоинты, гоночные чекпоинты, мап иконки, 3d-тексты, пикапы, актёры.

Примечание:

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

Примечание 2:

При указании последовательности используйте числа между 0 и 7 (только ID'ы существующих типов) и не задавайте одинаковые ID'ы дважды, иначе получите проблемы с созданием тех или иных элементов определённого типа.

Использование:

public OnGameModeInit()
{
//Создадим массив для работы с функцией, куда запишем порядок загрузки типов стримерских элементов
new types[STREAMER_MAX_TYPES] =
{
STREAMER_TYPE_MAP_ICON, //(STREAMER_TYPE_MAP_ICON задефайнен как 4) - этот тип будет загружаться самым первым
STREAMER_TYPE_RACE_CP, //(STREAMER_TYPE_RACE_CP = 3) - этот тип будет загружаться вторым
STREAMER_TYPE_CP, //(STREAMER_TYPE_CP = 2) - этот будет загружаться третьим
STREAMER_TYPE_OBJECT, //(STREAMER_TYPE_OBJECT = 0) - четвёртым
STREAMER_TYPE_ACTOR, //(STREAMER_TYPE_ACTOR = 7) - пятым
STREAMER_TYPE_3D_TEXT_LABEL, //(STREAMER_TYPE_3D_TEXT_LABEL = 5) - шестым
STREAMER_TYPE_AREA, //(STREAMER_TYPE_AREA = 6) - седьмым
STREAMER_TYPE_PICKUP //(STREAMER_TYPE_PICKUP = 1) - восьмым, самым последним
};

//В первый аргумент передали наш массив - types
//Во второй аргумент передали размер нашего массива - sizeof types
//По итогу: устанавливаем последовательность типов стримерских элементов в порядке их отображения
Streamer_SetTypePriority(types, sizeof types);
return 1;
}

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

Streamer_GetMaxItems

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


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

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

Возвращает:

Максимальное количество создаваемых стримером элементов.

Использование:

public OnGameModeInit()
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_3D_TEXT_LABEL
//По итогу: узнаём и выводим в консоль максимальное количество 3d-текстов, которое может быть создано через стример
printf("Max 3d-texts: %d", Streamer_GetMaxItems(STREAMER_TYPE_3D_TEXT_LABEL)); //По умолчанию лимит 3d-текстов равен -1 (т.е. фактически его нет), что в данном случае и выведет в лог
return 1;
}

Streamer_SetMaxItems

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


Streamer_SetMaxItems(type, items)
Параметры:

type: Тип элемента.
items: Максимальное количество элементов (по умолчанию лимитов нет, т.е. -1).

Возвращает:

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

Использование:

public OnGameModeInit()
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_3D_TEXT_LABEL
//Во второй аргумент передали максимальное количество элементов - 512
//По итогу: устанавливаем максимальное количество 3d-текстов, которое может быть создано через стример
Streamer_SetMaxItems(STREAMER_TYPE_3D_TEXT_LABEL, 512);
return 1;
}

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

Streamer_ToggleItemStatic

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


Streamer_ToggleItemStatic(type, id, toggle)
Параметры:

type: Тип элемента.
id: ID элемента.
toggle: 0 для отключения статичности, 1 для включения (по умолчанию элемент динамичен, т.е. 0).

Возвращает:

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

Использование:

public OnPlayerSelectDynamicObject(playerid, objectid, modelid, Float:x, Float:y, Float:z)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали сам ID элемента - objectid
//В третий аргумент передали состояние включения статичности - 1
//По итогу: делаем стримерский объект статичным
Streamer_ToggleItemStatic(STREAMER_TYPE_OBJECT, objectid, 1);
return 1;
}

Streamer_IsToggleItemStatic

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


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

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

Возвращает:

1, если стримерский элемент в данный момент статичен и 0, если нет.

Использование:

public OnDynamicActorStreamIn(actorid, forplayerid)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_ACTOR
//Во второй аргумент передали сам ID элемента - actorid
//По итогу: узнаём, является ли стримерский актёр статическим
if(Streamer_IsToggleItemStatic(STREAMER_TYPE_ACTOR, actorid)) SendClientMessage(forplayerid, -1, "Вы видите статического стримерского актёра"); //При попадании стримерского актёра в стрим игрока выведем ему это сообщение, если наш актёр при этом статичен
else SendClientMessage(forplayerid, -1, "Вы видите динамического стримерского актёра"); //Иначе выведем это
return 1;
}

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

Streamer_GetRadiusMultiplier

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


Streamer_GetRadiusMultiplier(type, &Float:multiplier, playerid = -1)
Параметры:

type: Тип элемента.
multiplier: множитель (с типом Float).
playerid: ID игрока (если не указывать, то множитель будет узнан для всех).

Возвращает:

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

Использование:

public OnGameModeInit()
{
//Создадим переменную, в которую запишется множитель
new Float:multiplier;

//В первый аргумент передали тип элемента - STREAMER_TYPE_OBJECT
//Во второй аргумент передали переменную, в которую хотим записать множитель - multiplier
//В третий аргумент передали ID игрока - в данном случае -1 означает, что мы узнаём не для конкретного игрока, а для всех
//По итогу: узнаём множитель текущего радиуса стрима для объектов для всех игроков
Streamer_GetRadiusMultiplier(STREAMER_TYPE_OBJECT, multiplier, -1);

//Выводим узнанное в консоль
printf("Radius multiplier for objects: %f", multiplier); //По умолчанию выведет 1.0
return 1;
}

Streamer_SetRadiusMultiplier

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


Streamer_SetRadiusMultiplier(type, Float:multiplier, playerid = -1)
Параметры:

type: Тип элемента.
multiplier: множитель (с типом Float) (по умолчанию 1.0).
playerid: ID игрока (если не указывать, то множитель будет задан для всех).

Возвращает:

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

Примечание:

Как пример, множитель с радиусом 0.5 будет уменьшать радиус стрима всех элементов указанного типа наполовину. Таким образом игрок должен быть в два раза ближе обычного для того, чтобы элемент появился у него в стриме (подгрузился для него).

Использование:

public OnGameModeInit()
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_PICKUP
//Во второй аргумент передали множитель радиуса стрима - 0.5
//В третий аргумент передали ID игрока - в данном случае -1 означает, что мы задаём не для конкретного игрока, а для всех
//По итогу: задаём множитель радиуса стрима (а именно сокращаем дистанцию стрима в 2 раза) для пикапов для всех игроков
Streamer_SetRadiusMultiplier(STREAMER_TYPE_PICKUP, 0.5, -1);
return 1;
}

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

Streamer_ToggleItemInvAreas

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


Streamer_ToggleItemInvAreas(type, id, toggle)
Параметры:

type: Тип элемента.
id: ID элемента.
toggle: 0 для отображения элемента только внутри стримерской зоны, 1 для отображения только вне (по умолчанию 0).

Возвращает:

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

Использование:

public OnGameModeInit()
{
//Создаём динамическую зону (вида окружности) с радиусом 30 метров
new areaid = CreateDynamicCircle(1947.7665, 1292.1793, 30.0);

//Создаём динамическую мап иконку (жёлтый маркер) на тех же координатах в середине стримерской зоны
new iconid = CreateDynamicMapIcon(1947.7665, 1292.1793, 10.5672, 0, 0xFFFF00FF, .areaid = areaid); //.areaid - обращение к нужному аргументу по его имени минуя все остальные между; в данном случае указали привязку нашей мап иконки к созданной зоне

//В первый аргумент передали тип элемента - STREAMER_TYPE_MAP_ICON
//Во второй аргумент передали сам ID элемента - iconid
//В третий аргумент передали состояние включения инверсии - 1
//По итогу: делаем инверсию работы стримерской зоны для нашей созданной стримерской мап иконки в ней
Streamer_ToggleItemInvAreas(STREAMER_TYPE_MAP_ICON, iconid, 1);
return 1;
}

/*
Теперь мап иконка будет видна только находясь на расстоянии более 30 метров от неё. При приближении к ней она будет исчезать.
*/

Streamer_IsToggleItemInvAreas

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


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

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

Возвращает:

1, если работа стримерских зон для стримерского элемента в данный момент инвертирована и 0, если нет.

Использование:

public OnPlayerPickUpDynamicPickup(playerid, pickupid)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_PICKUP
//Во второй аргумент передали сам ID элемента - pickupid
//По итогу: узнаём, инвертирована ли работа стримерских зон для стримерского пикапа
if(Streamer_IsToggleItemInvAreas(STREAMER_TYPE_PICKUP, pickupid)) SendClientMessage(playerid, -1, "Инверсия стримерских зон для этого пикапа включена"); //При подборе пикапа выведем игроку это сообщение, если работа зон, к которым он привязан, инвертирована
else SendClientMessage(playerid, -1, "Инверсия стримерских зон для этого пикапа отключена"); //Иначе выведем это
return 1;
}

Отлично, теперь давайте познакомимся с функциями, которые включают некоторые дополнительные (отключенные по умолчанию) паблики стримера, которые могут нам пригодиться. Первым делом стоит начать с того, что стример имеет два паблика, которые вызываются при входе/выходе некоторых стримерских элементов в зону прорисовки какого-либо игрока (Streamer_OnItemStreamIn и Streamer_OnItemStreamOut). Далее рассмотрим сами функции включения этих пабликов - Streamer_ToggleItemCallbacks и Streamer_IsToggleItemCallbacks.

Streamer_ToggleItemCallbacks

Эта функция включает/отключает вызов стримерских пабликов (Streamer_OnItemStreamIn (https://github.com/samp-incognito/samp-streamer-plugin/wiki/Callbacks) и Streamer_OnItemStreamOut (https://github.com/samp-incognito/samp-streamer-plugin/wiki/Callbacks)) для указанного стримерского элемента.


Streamer_ToggleItemCallbacks(type, id, toggle)
Параметры:

type: Тип элемента.
id: ID элемента.
toggle: 0 для отключения вызова пабликов, 1 для включения (по умолчанию 0).

Возвращает:

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

Использование:

public OnGameModeInit()
{
//Создаём динамическую мап иконку (знак вопроса)
new iconid = CreateDynamicMapIcon(1947.7665, 1292.1793, 10.5672, 37, 0xFFFF00FF);

//В первый аргумент передали тип элемента - STREAMER_TYPE_MAP_ICON
//Во второй аргумент передали сам ID элемента - iconid
//В третий аргумент передали состояние включения вызова стримерских пабликов - 1
//По итогу: включаем вызов стримерских пабликов входа/выхода из стрима для нашей созданной стримерской мап иконки
Streamer_ToggleItemCallbacks(STREAMER_TYPE_MAP_ICON, iconid, 1);
return 1;
}

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

public Streamer_OnItemStreamIn(type, STREAMER_ALL_TAGS id)
{
printf("Streamer_OnItemStreamIn(type %d, id %d)", type, _:id); //_: - обнуление тега переменной, чтобы не было варнинга
return 1;
}

public Streamer_OnItemStreamOut(type, STREAMER_ALL_TAGS id)
{
printf("Streamer_OnItemStreamOut(type %d, id %d)", type, _:id); //_: - обнуление тега переменной, чтобы не было варнинга
return 1;
}

Streamer_IsToggleItemCallbacks

Эта функция проверяет, включен ли вызов стримерских пабликов Streamer_OnItemStreamIn (https://github.com/samp-incognito/samp-streamer-plugin/wiki/Callbacks) и Streamer_OnItemStreamOut (https://github.com/samp-incognito/samp-streamer-plugin/wiki/Callbacks) (включена ли функция Streamer_ToggleItemCallbacks) для указанного стримерского элемента.


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

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

Возвращает:

1, если вызов стримерских пабликов в данный момент включен и 0, если нет.

Использование:

public OnPlayerPickUpDynamicPickup(playerid, pickupid)
{
//В первый аргумент передали тип элемента - STREAMER_TYPE_PICKUP
//Во второй аргумент передали сам ID элемента - pickupid
//По итогу: узнаём, включен ли вызов стримерских пабликов входа/выхода из стрима для стримерского пикапа
if(Streamer_IsToggleItemCallbacks(STREAMER_TYPE_PICKUP, pickupid)) SendClientMessage(playerid, -1, "Вызов стримерских пабликов входа/выхода из стрима для этого пикапа включен"); //При подборе пикапа выведем игроку это сообщение, если вызов дополнительных пабликов для него включен
else SendClientMessage(playerid, -1, "Вызов стримерских пабликов входа/выхода из стрима для этого пикапа отключен"); //Иначе выведем это
return 1;
}

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

Streamer_ToggleErrorCallback

Эта функция включает/отключает вызов паблика ошибок стримера (Streamer_OnPluginError (https://github.com/samp-incognito/samp-streamer-plugin/wiki/Callbacks)).


Streamer_ToggleErrorCallback(toggle)
Параметры:

toggle: 0 для отключения вызова паблика ошибок, 1 для включения (по умолчанию 0).

Возвращает:

Всегда возвращает 1.

Примечание:

Это может быть особенно полезно в сочетании с функцией PrintAmxBacktrace из плагина CrashDetect (https://github.com/Zeex/samp-plugin-crashdetect), что позволит скрипту точно определить, где именно произошла ошибка.

Использование:

public OnGameModeInit()
{
//В первый аргумент передали состояние включения вызова паблика ошибок - 1
//По итогу: включаем вызов паблика ошибок выполнения у стримера, перенаправляя все ошибки в него вместо их вывода в консоль
Streamer_ToggleErrorCallback(1);
return 1;
}

//Теперь при возникновении любой ошибки выполнения у стримера будет вызываться этот паблик

public Streamer_OnPluginError(const error[])
{
for(new i = GetPlayerPoolSize(); i >= 0; --i)
{
if(IsPlayerAdmin(i)) SendClientMessage(i, -1, error); //Рассылаем эту ошибку всем RCON админам сервера, из тех кто в игре
}
return 1;
}

Streamer_IsToggleErrorCallback

Эта функция проверяет, включен ли вызов паблика ошибок стримера (включена ли функция Streamer_ToggleErrorCallback).


Streamer_IsToggleErrorCallback()
Параметры:

Данная функция не имеет параметров.

Возвращает:

1, если вызов паблика ошибок стримера включен и 0, если нет.

Использование:

public OnGameModeInit()
{
//Узнаём, включен ли вызов паблика ошибок выполнения у стримера
if(Streamer_IsToggleErrorCallback()) print("Вызов паблика ошибок стримера включен, все возможные ошибки НЕ будут отображаться в логе сервера"); //При запуске сервера выведем в лог это сообщение, если вызов паблика ошибок стримера включен
else print("Вызов паблика ошибок стримера отключен, все возможные ошибки будут отображаться в логе сервера"); //Иначе выведем это
return 1;
}

Заключение

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

Домашнее задание

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

Написать функцию, которая будет устанавливать порядок (приоритет) подгрузки различных типов стримерских элементов именно в такой последовательности: сначала гоночные чекпоинты, потом обычные чекпоинты, потом мап иконки, стримерские зоны, пикапы, объекты, 3d-тексты, и, наконец, актёры.
Примерный шаблон функции: здесь всё на ваше усмотрение.
Должна возвращать: 1 в случае успешного выполнения и 0 в случае неудачи.
Написать функцию, которая будет создавать два разных объекта на одном месте, причём на большом расстоянии игрока от объектов показан должен быть лишь первый из них, а при приближении игрока на 30 метров - только второй объект. Разрешено использование всего лишь одной стримерской зоны и запрещено использовать паблики входа/выхода из динамической зоны, а также запрещено самостоятельное удаление любого из объектов. Иды двух объектов на ваш выбор (но они оба разные), а дистанция прорисовки у этих объектов должна быть одинаковой.
Примерный шаблон функции: CreateShiftingObjects(objectid1, objectid2);
Должна возвращать: 1 в случае успешного выполнения и 0 в случае неудачи.
Написать реализацию, которая будет записывать ошибки выполнения функций стримера в отдельный лог файл с названием "streamer_log.txt", при этом также записывая их и в основной лог сервера.
Примерный шаблон реализации: здесь всё на ваше усмотрение.

Ссылки по теме

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)

Elrmrnt-Kritik
26.03.2018, 01:08
Streamer_ToggleItemStatic

Хотел бы уточнить. Если будет игнорироваться дистанция, то объект будет создан независимо от того, находится ли сам объект в зоне видимости игрока? Этим можно пользоваться, например, чтобы при появлении где-нибудь в интерьере (самодельном) не проваливаться под пол? Либо я все же неправильно понимаю, что есть статический объект?

Nexius_Tailer
27.03.2018, 01:30
Хотел бы уточнить. Если будет игнорироваться дистанция, то объект будет создан независимо от того, находится ли сам объект в зоне видимости игрока? Этим можно пользоваться, например, чтобы при появлении где-нибудь в интерьере (самодельном) не проваливаться под пол? Либо я все же неправильно понимаю, что есть статический объект?
По сути да, дистанция -1 говорит о том, что объект (или что бы это ни было) будет отображаться стримером на любых дистанциях, соответственно он должен быть всегда создан для игрока как и обычный статический объект.

#Moore
08.08.2018, 05:46
По сути да, дистанция -1 говорит о том, что объект (или что бы это ни было) будет отображаться стримером на любых дистанциях, соответственно он должен быть всегда создан для игрока как и обычный статический объект.

Отсюда возникает вопрос, чем это будет отличаться от обычного статического объекта, ведь стример в первую очередь используют, для того чтобы избежать лимита в 1000 объектов. А в данном случае, будет забираться с лимита один слот что при статическом объекте, что при этом способе.

DeimoS
08.08.2018, 12:06
Отсюда возникает вопрос, чем это будет отличаться от обычного статического объекта, ведь стример в первую очередь используют, для того чтобы избежать лимита в 1000 объектов. А в данном случае, будет забираться с лимита один слот что при статическом объекте, что при этом способе.

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

Ну а если и будет, то нет, такой объект будет идентичен созданному CreatePlayerObject, коим он и является. И никаких отличий со статическим объектом быть не должно в данном случае. Стример ведь достигает обхода лимита не каким-то магическим образом, а просто создаёт CreatePlayerObject в определённом радиусе вокруг игрока, удаляя все остальные, не входящие в этот радиус. Соответственно, вся суть стримера в том, что он, во-первых, хранит координаты всех объектов у себя в памяти, а, во-вторых, сопоставляет координаты игроков с координатами объектов и создаёт/удаляет те, которые находятся близко/далеко относительно игрока.