PDA

Просмотр полной версии : [Include] PrivateArea.inc - создание приватных зон



punkochel
17.11.2020, 16:34
PrivateArea.inc
PrivateArea.inc - это библиотека, которая позволяет создавать приватные зоны на сервере в SA:MP.

Как это работает: Когда игрок пытается зайти в приватную зону, его откидывает обратно.

Ограничения:

Для работы с данной библиотекой необходимо иметь streamer (https://github.com/samp-incognito/samp-streamer-plugin/releases) и foreach (https://github.com/karimcambridge/samp-foreach/releases).
Создавать можно только зоны с типом Sphere (сфера).

Константы:

MAX_PRIVATE_AREA - Максимальное количество созданных приватных зон (по умолчанию 50);
PRIVATE_AREA_NONE - Приватной зоны не существует;
PRIVATE_AREA_FULL_LIMIT - Превышен лимит создания приватных зон.

Функции:
public OnPlayerTriedEnterPrivateArea(playerid, areaid);
CreatePrivateArea(Float:x, Float:y, Float:z, Float:size, worldid = -1, interiorid = -1, playerid = -1, priority = 0);
DestroyPrivateArea(areaid);
DenyEntryToPrivateArea(areaid, playerid = -1);
AllowEntryToPrivateArea(areaid, playerid = -1);
IsPlayerAddInPrivateArea(playerid, areaid);

Описание функций:

OnPlayerTriedEnterPrivateArea - Автовызываемая функция, которая вызывается когда игрок пытается войти в приватную зону.


Параметры:

playerid - ID игрока;
areaid - ID динамической зоны.


CreatePrivateArea - Создает приватную зону на сервере.


Возвращаемые значения:

ID динамической зоны в случае успеха;
PRIVATE_AREA_FULL_LIMIT - если превышен лимит создания приватных зон.
Параметры:

x, y, z - координаты зоны;
size - размер зоны;
worldid - виртуальный мир (по умолчанию -1);
interiorid - интерьер (по умолчанию -1);
playerid - укажите Id игрока, если необходимо создать зону только для него (по умолчанию -1);
priority - установить приоритет загрузки зоны (по умолчанию 0).


DestroyPrivateArea - Уничтожает приватную зону с сервера.


Возвращаемые значения:

1 - если приватная зона была успешно удалена;
PRIVATE_AREA_NONE - если приватной зоны не существует.
Параметры:

areaid - ID динамической зоны;


DenyEntryToPrivateArea - Запрещает игроку входить в приватную зону.


Возвращаемые значения:

1 - в случае успеха;
0 - если ID игрока меньше 0 или больше MAX_PLAYERS-1;
PRIVATE_AREA_NONE - если приватной зоны не существует.
Параметры:

areaid - ID динамической зоны;
playerid - ID игрока которому нужно запретить вход (по умолчанию -1 (запрещает входим всем)).


AllowEntryToPrivateArea - Разрешает игроку входить в приватную зону.


Возвращаемые значения:

1 - в случае успеха;
0 - если ID игрока меньше 0 или больше MAX_PLAYERS-1;
PRIVATE_AREA_NONE - если приватной зоны не существует.
Параметры:

areaid - ID динамической зоны;
playerid - ID игрока которому нужно разрешить вход (по умолчанию -1 (разрешает входим всем)).


IsPlayerAddInPrivateArea - Проверяет добавлен ли игрок в приватную зону.


Возвращаемые значения:

1 - если игрок добавлен в приватную зону;
0 - если ID игрока меньше 0 или больше MAX_PLAYERS-1, либо игрок не добавлен в приватную зону;
PRIVATE_AREA_NONE - если приватной зоны не существует.
Параметры:

playerid - ID игрока;
areaid - ID динамической зоны.


Пример использования:
new PrivateArea;
public OnGameModeInit() {

PrivateArea = CreatePrivateArea(0.0, 0.0, 0.0, 100.0);
DenyEntryToPrivateArea(PrivateArea);
return 1;
}
public OnPlayerTriedEnterPrivateArea(playerid, areaid) {

if(areaid == PrivateArea)
SendClientMessage(playerid, -1, !"Запретная территория. Вход запрещен!");
return 1;
}




Version 1.1 (17.11.2020):
- Добавлена функция IsPlayerAddInPrivateArea(playerid, areaid);

Version 1.2 (17.11.2020):
- Исправлена ошибка при записи координат, когда игрок находится в автомобиле;

Автор статьи и библиотеки: punkochel (https://pro-pawn.ru/member.php?9227-punkochel)
Скачать Include : GitHub (https://github.com/punkochel/PrivateArea.inc)
*Примечание: Данная версия инклуда содержит в себе функции, логика работы которых будет пересмотрена в ближайшее время. Вы можете его использовать, но выход новых версий возможно заставит вас изменить некоторые параметры.


*Исключительно для pro-pawn.ru
Копирование данной статьи на других ресурсах без разрешения автора или Daniel_Cortez (https://pro-pawn.ru/member.php?100-Daniel_Cortez) запрещено!

DeimoS
18.11.2020, 02:52
Во-первых, у тебя функция DenyEntryToPrivateArea не будет работать корректно при указании "-1", ибо ты используешь foreach, который добавит только игроков, которые есть на сервере (соответственно, твой код из примера не добавит вообще никого из игроков в список запрещённых). Вполне возможно, что есть ещё какие-то недочёты. Буквально мельком глянул код.

Во-вторых, почему не создал итератор для своих зон?

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

Ну и не проще ли было бы в CreatePrivateArea возвращать не ID динамической зоны, а индекс массива? Тогда можно будет избавиться большинства циклов с перебором всех твоих приватных зон только ради того, чтоб найти нужную динамическую зону. У тебя всё равно нигде нет нужды давать пользователю возможность обращаться именно к динамической зоне, а не к твоему массиву.

UPD: Так же тебе стоит как-то контролировать момент с указанием конкретного ID игрока в CreatePrivateArea, дабы нельзя было потом в DenyEntryToPrivateArea/AllowEntryToPrivateArea манипулировать приватной зоной для тех игроков, для которых не создаётся динамическая зона. Лучше всего будет просто избавиться от массива "BannedPlayerId" и перенести функционал разрешения/запрета на параметр "playerid" динамической зоны, используя функции стримера Streamer_AppendArrayData/Streamer_RemoveArrayData. Это и решит упомянутую проблему, и сделает код более оптимизированным, ибо у тебя и память освободиться, и, в целом, код не будет срабатывать для тех игроков, для кого не включен запрет.

punkochel
18.11.2020, 07:29
Спасибо за идеи, обязательно в скором времени выпущу релиз.

Seviel
19.11.2020, 12:38
На мой скромный взгляд лучше давать возможность создавать динамические зоны самим, а после уже можно запрещать в них заходить.

PrivateArea = CreateDynamicSphere(0.0, 0.0, 0.0, 100.0);
DenyEntryToPrivateArea(PrivateArea);


А координаты узнавать через направление от центра до ближайшей точки доступной игроку./


static Float:ax, Float:ay, Float:az;
if(GetPlayerPos(playerid, ax, ay, az))
{
static
Float:x, Float:y, Float:z,
Float:angle,
Float:size;

Streamer_GetItemPos(STREAMER_TYPE_AREA, areaid, x, y, z);
angle = atan2(y-ay, x-ax) + 90.00; // - Вычисляем угол поворота обратный от центра зоны

Streamer_GetFloatData(STREAMER_TYPE_AREA, STREAMER_TYPE_AREA, E_STREAMER_SIZE, size);

// - Вычисляем координаты за границы зоны(может правильнее size / 2) не проверял

ax += ((size + 15.0) * floatsin(-angle, degrees));
ay += ((size + 15.0) * floatcos(-angle, degrees));

SetPlayerPos(playerid, ax, ay, az);
}


Ну или сохранять позицию игрока всегда.