[Include] W_Points
#1

Здравствуйте!


Представляю вашему вниманию "стример" точек.

Что же это такое спросите вы - это быстрое нахождение в какой из созданных точек находится игрок.
Создан специально чтобы искоренить медленную и не рациональную конструкцию вида:
PHP код:
stock IsPlayerIn(playerid)
{
    for(new 
0sizeof(coords); i++)
        if(
IsPlayerInRangeOfPoint(playerid1.0coords[i][0], coords[i][1], coords[i][2]))return 1;
    return 
0;

Основан он на зональной предварительной отсортировки, что придаёт значительную скорость обработки, так как откидывается большая часть лишних проверок.

Область применения:
Quote:

- заменяем пикапы для домов/бизов на точки.
- создание ворот
- место заправки
- возможность создать псевдочекпойнты или мины.
- отслеживание в какой точке находится игрок, для захвата территории, пополнение очков и т.п.

Основные функции:
PHP код:
native IsValidPoint(pointid);// Существует ли точка
native CreatePoint(Float:xFloat:yFloat:zFloat:rworldid=-1interior=-1);// Cоздаёт точку (х, у, z, радиус, вирт.мир, интерьер). Вернёт ид точки, иначе ид ошибки.
native DestroyPoint(pointid);// Удаляет точку
native DestroyAllPoint();// Удаляет все точки
native SetPointPos(pointidFloat:xFloat:yFloat:z);//Переместить точку
native GetPointPos(pointid, &Float:x, &Float:y, &Float:z);//Узнать координаты точки
native SetPointRadius(pointidFloat:r);//Установить радиус точки
native GetPointRadius(pointid, &Float:r);//Узнать радиус точки
native SetPointInterior(pointidinterior);//Установить интерьер точки
native GetPointInterior(pointid);//Узнать интерьер точки
native SetPointVirtualWorld(pointidworldid);//Установить вирт.мир точки
native GetPointVirtualWorld(pointid);//Узнать вирт.мир точки
native GetPlayerPoint(playeridmode=0); //Узнает в какой точке находится игрок. Возвращает ид найденной точки.
native GetPlayerMultiPoint(playeridMP[], Size);//Узнает в каких точках находится игрок. Возвращает количество найденных точек
native GetVehiclePoint(vehicleidmode=0);//Узнает в какой точке находится транспорт (самую близлежащую, самую близлежащую с проверкой радиуса, самую первую которая входит в радиус)
native GetVehicleMultiPoint(vehicleidMP[], Size);//Узнает в каких точках находится транспорт 
Quote:

GetPlayerPoint(playerid, 0); Ищет самую близлежащую точку в которой находится игрок.
GetPlayerPoint(playerid, 1); Ищет самую близлежащую точку даже если игрок не находится в ней.
GetPlayerPoint(playerid, 2); Ищет до первой точки в которой находится игрок.
GetPlayerMultiPoint(playerid, MP[], Size); Ищет все точки в которых находится игрок пока они не закончатся или не достигнут Size.

Небольшой Тест всего 40,000 точек, симуляция 1000 игроков. Ищется самая близлежащая точка. Для правильности теста нужно быть на сервере, возле нулевых координат!

Create W_Points 473 ms
GetW_Point 20 ms

Create StreamerPoints 35 ms
GetStreamerPoint 329 ms

GetClassicPoint 11479 ms

y_areas выдаёт для одного игрока ~5 ms, осталось домножить на 1000.

Внимание!
1) Настоятельно рекомендую не ставить радиус больше MAX_POINTS_SETKA_DLINA, так как при нахождения точки может возникнуть казус: вы входите в радиус но точка не определяется. Связано это с отсутствием ссылки на точку.
2) Поддержка интерьеров и виртуальных миров по умолчанию отключена. Для того чтобы включить выполняем следующие:
PHP код:
#define PointWorld //включаем вирт.мир
#define PointInterior //включаем интерьер
#include <W_PS> //подключаем инклуд 
<<< Примеры >>>
Использование GetPlayerMultiPoint:
PHP код:
new pointarray[32];//создали массив куда пишем иды точек.
new kolichestvo=GetPlayerMultiPoint(playeridpointarraysizeof(pointarray));//поиск точек, вернёт количество найденных точек.
for(kolichestvo=kolichestvo-1kolichestvo > -1kolichestvo--)printf("pointid = %d",pointarray[kolichestvo]); 
Псевдочекпойнт:
PHP код:
new Point[MAX_PLAYERS];//Куда нибудь в начало, хранит ид точки в которой находится игрок.
stock PointUpdate(playerid)//В любой таймер с перебором игроков
{
    new 
newppoint=GetPlayerPoint(playerid);//Ищем самую близлежайшую точку в которой находится игрок
    
if(Point[playerid] != newppoint)//Если точка отличается от старой.
    
{
        if(
Point[playerid] != 0)    OnPlayerLeavePoint(playeridPoint[playerid]);//Если мы были в точке
        
if(newppoint != 0)            OnPlayerEnterPoint(playeridnewppoint);//Если новая точка точка.
        
Point[playerid]=newppoint;//Запомним точку
    
}
    return 
1;
}
stock OnPlayerLeavePoint(playeridpointid)
{
//...
}
stock OnPlayerEnterPoint(playeridpointid)
{
//...

Пример 3:
PHP код:
#include <a_samp>
#define MAX_POINTS (10)
#define MAX_POINTS_TO_STREAM (10)
#define PointWorld
#define PointInterior
#define DeBug
#include <W_PS>
#define Biznes (1)
#define Home (2)
new PointData[3][MAX_POINTS+1 char];
new 
BizKolvo;
new 
HomeKolvo;
new 
Timer;
new 
Point[MAX_PLAYERS];//Куда нибудь в начало, хранит ид точки в которой находится игрок.
//==============================================================================
public OnFilterScriptInit()
{
     
Timer=SetTimer("PointUpdate",100,1);
    return 
1;
}
public 
OnFilterScriptExit()
{
     
KillTimer(Timer);
    return 
1;
}
public 
OnPlayerCommandText(playeridcmdtext[])
{
    if(
strcmp("/biz"cmdtexttrue4) == 0)
    {
        
CreateBiz(playerid);
        return 
1;
    }
    if(
strcmp("/home"cmdtexttrue5) == 0)
    {
        
CreateHome(playerid);
        return 
1;
    }
    if(
strcmp("/del"cmdtexttrue4) == 0)
    {
        
DestroyPoint(MAX_POINTS);
        return 
1;
    }
    if(
strcmp("/pos"cmdtexttrue4) == 0)
    {
        new 
Float:x,Float:y,Float:z;
        
GetPlayerPos(playeridx,y,z);
        
SetPointPos(MAX_POINTSxyz);
        return 
1;
    }
    return 
0;
}
//==============================================================================
forward PointUpdate();
public 
PointUpdate()//В любой таймер с перебором игроков
{
    for(new 
playeridplayerid MAX_PLAYERSplayerid++)
    if(
IsPlayerConnected(playerid))
    {
        new 
newppoint=GetPlayerPoint(playerid);//Ищем самую близлежайшую точку в которой находится игрок
        
if(Point[playerid] != newppoint)//Если точка отличается от старой.
        
{
            if(
Point[playerid] != 0)    OnPlayerLeavePoint(playeridPoint[playerid]);//Если мы были в точке
            
if(newppoint != 0)            OnPlayerEnterPoint(playeridnewppoint);//Если новая точка точка.
            
Point[playerid]=newppoint;//Запомним точку
        
}
    }
    return 
1;
}
stock OnPlayerLeavePoint(playeridpointid)
{
    new 
str[128];
    if(
PointData[0]{pointid} == Homeformat(str,sizeof(str),"Вы покинули дом номер %d, хозяин %d",PointData[1]{pointid},PointData[2]{pointid});
    else 
format(str,sizeof(str),"Вы покинули бизнес номер %d, хозяин %d",PointData[1]{pointid},PointData[2]{pointid});
    return 
SendClientMessage(playerid,-1,str);
}
stock OnPlayerEnterPoint(playeridpointid)
{
    new 
str[128];
    if(
PointData[0]{pointid} == Homeformat(str,sizeof(str),"Вы вошли в дом номер %d, хозяин %d",PointData[1]{pointid},PointData[2]{pointid});
    else 
format(str,sizeof(str),"Вы вошли в бизнес номер %d, хозяин %d",PointData[1]{pointid},PointData[2]{pointid});
    return 
SendClientMessage(playerid,-1,str);
}
stock CreateBiz(playerid)
{
    new 
Float:x,Float:y,Float:z;
    
GetPlayerPos(playeridx,y,z);
    new 
p=CreatePoint(x,y,z10.0);
    if(
1)
    {
        if(
== 0printf("Привышено максимальное количество точек.");
        if(
== -1)printf("Привышено максимальное количество точек в чанке.");
        if(
== -2)printf("Поддержка вирт.миров отключена!");
        if(
== -3)printf("Поддержка интерьеров отключена!");
        return 
0;
    }
    
BizKolvo++;
    
PointData[0]{p}=Biznes;//Запомним тип точки
    
PointData[1]{p}=BizKolvo;//Запомни ид бизнеса
    
PointData[2]{p}=playerid;//Запомним владельца
    
return BizKolvo;
}
stock CreateHome(playerid)
{
    new 
Float:x,Float:y,Float:z;
    
GetPlayerPos(playeridx,y,z);
    new 
p=CreatePoint(x,y,z10.0);
    if(
1)
    {
        if(
== 0printf("Привышено максимальное количество точек.");
        if(
== -1)printf("Привышено максимальное количество точек в чанке.");
        if(
== -2)printf("Поддержка вирт.миров отключена!");
        if(
== -3)printf("Поддержка интерьеров отключена!");
        return 
0;
    }
    
HomeKolvo++;
    
PointData[0]{p}=Home;//Запомним тип точки
    
PointData[1]{p}=HomeKolvo;//Запомни ид дома
    
PointData[2]{p}=playerid;//Запомним владельца
    
return HomeKolvo;

>> Скачать W_Points v2.3: SolidFiles
>> Просмотреть W_Points v2.3: Pastebin

>> Скачать W_Points v2.1: SolidFiles
>> Просмотреть W_Points v2.1: Pastebin

W_Points v2.1:
-Добавлен поиск точек для транспорта.
-Исправлен баг в GetPlayerPoint(playerid, 2); связанный с лишним кодом.
W_Points v2.2:
-Исправлены мелкие ошибки.
-Новый метод поиска предложенный AirKite
W_Points v2.3:
Исправлено перемещение точки SetPointPos.
Reply
#2

pawn Код:
#define MAX_PL 200              //  Максимальное кол-во игроков
зачем это тут, стандартного дефайна мало?
pawn Код:
#define INVALID_POINT_ID                        (0xFFFFFFFFFFFF0001)
а за это убивать надо!?

Quote:
Originally Posted by White_116
Посмотреть сообщение
- заменяем пикапы для домов/бизов на точки.
а зачем, они же лучше?
Reply
#3

Quote:

а за это убивать надо!?

- делал под себя =)
Quote:

Цитата: Сообщение от White_116
Quote:

- заменяем пикапы для домов/бизов на точки.

а зачем, они же лучше?

ну пока не упрёшся в лемит, далее идёт стример а это время и нагрузка.
Reply
#4

Quote:
Originally Posted by White_116
Посмотреть сообщение
- делал под себя =)

ну пока не_упрёшься в лимит, далее идёт стример, а это время и нагрузка.
-1, не находишь что проще?
по-моему стример куда большее время и нагрузка? А если учесть что сейчас лимит пикапов 4096, и на подьем есть дефолтное событие, то... я не понимаю.
Reply
#5

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

Вот допустим, ты заминировал всю карту 30,000 минами ловушками. Как будем искать, что чел наступил на мину? Проверять в какой зоне из 30,000 мин чел находится, или же отсортировать и смотреть ближайшие (максимум 9*30 - в настройках меняется)
Reply
#6

Quote:
Originally Posted by White_116
Посмотреть сообщение
зразу цепляются
зразы зуки цепляются, да.. Не ленись, проверяй пост на грамота.ру
Reply
#7

Quote:
Originally Posted by Makar93
Посмотреть сообщение
зразы зуки цепляются, да.. Не ленись, проверяй пост на грамота.ру
во всех браузерах есть проверка орфографии.
Reply
#8

еще проверка орфографии есть в школе.базовые правила хотяб знать надо)
Reply
#9

А я думал в теме релизов надо обсуждать их, а не грамоту.
Reply
#10

ИМХО некрасиво публиковать инклюды хотя бы без минимальной инструкции
Reply
#11

Обновил!
Quote:

#define MAX_PL 200 // Максимальное кол-во игроков
зачем это тут, стандартного дефайна мало?

- потерял из вида (удалено)
Quote:

ИМХО некрасиво публиковать инклюды хотя бы без минимальной инструкции

- учтено, кинул основные функции. (хотя пример был в папке filterscripts)
Quote:

А я думал в теме релизов надо обсуждать их, а не грамоту.

- нужно же хоть к чему-то прикопаться. Просьба почистить это бессмысленный флуд. Не отрицаю что я безграмотен
Reply
#12

Не у всех есть вермя и желание рытся в примерах... Неговоря и о самом inlude. Теперь отлично!
Reply
#13

Ура, это свершилось. Новая версия уважаемые форумчане.
В 2.0 переписан весь код, сверху до низу. Проведена значительная оптимизация, расширил функционал. В общем, смотрим не стесняемся.
Reply
#14

Название не удачное, будто бы Waypoints.
Reply
#15

Quote:
Originally Posted by AirKite
View Post
Название не удачное, будто бы Waypoints.
Да, возможно. Кроме как "точки" в голову ничего не пришло, чтобы правильно ассоциировать инклуд.
P.S. Маленькое обновление.
Reply
#16

Полезно, очень. Спасибо.
Reply
#17

Quote:
Originally Posted by White_116
View Post
Да, возможно. Кроме как "точки" в голову ничего не пришло, чтобы правильно ассоциировать инклуд.
P.S. Маленькое обновление.
Ну как же, а Chunks? W_ChunksPos или W_PosChunks.

Мельком глянул код, в принципе всё понятно. Метод заключается в разбиении площади по сетке, на чанки (части, блоки). Правда далеко не всегда рациональный способ по сравнению с IsPlayerInRangeOfPoint, особенно по отношению к твоему инклуду, а именно это 2D ориентация точек, вместо 3D.
Reply
#18

Quote:
Originally Posted by AirKite
View Post
Ну как же, а Chunks? W_ChunksPos или W_PosChunks.

Мельком глянул код, в принципе всё понятно. Метод заключается в разбиении площади по сетке, на чанки (части, блоки). Правда далеко не всегда рациональный способ по сравнению с IsPlayerInRangeOfPoint, особенно по отношению к твоему инклуду, а именно это 2D ориентация точек, вместо 3D.
Дело в том что можно и 3д разбиение но это уже третья степень, памяти выделять нужно много. Тем более тут итак уже выделено достаточно много, реально может всего задействовано 100 чанков вместо 10000(настраивается). Сами понимаете что павн язык статичный, т.е. в нём нет динамических массивов. Кто-то скажет что можно использовать setproperty() и getproperty(), но они медленные! Поэтому точки сортируются в двухмерной сетке а проверяются уже так как и должны в 3д. И ещё из-за этого ограничение мира стоит. Да и не так уж сильно важна высота, ведь в основном всё можно рассматривать в 2д.
Да стоит заметить что ради 10 проверок на IsPlayerInRangeOfPoint не разумно использовать. Рассчитан на 50 и более.

Основная задача это снизить количество проверяемых точек!

P.S. Можно снять ограничение мира. Для этого я и придумал вот это. Но опять таки динамика нужна.
Reply
#19

Идея с чанками гуд, код более или менее симпотный, при большом количестве поинтов это естественно будет быстрее чем обычный перебор координат. Но если же, перебор мелкий, неактуально вовсе.
Reply
#20

Кстати идея не нова, подобную реализацию видел ещё в лохматые времена для стримера.
Quote:
Originally Posted by White_116
View Post
точки сортируются в двухмерной сетке а проверяются уже так как и должны в 3д.
Код смотрел мельком, не увидел и сам недодумал. Сортировать в 3D в принципе не целесообразно с учётом требуемой для этого памяти. Касательно проблем с pawn, достаточно перевести всё в плагин.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)