Форум Pawn-Wiki.Ru - Воплоти мечту в реальность!: Убираем циклы и массивы с помощью стримера - Форум Pawn-Wiki.Ru - Воплоти мечту в реальность!

Перейти к содержимому

  • (4 Страниц) +
  • 1
  • 2
  • 3
  • Последняя »
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

[ Урок ]
Убираем циклы и массивы с помощью стримера Об этом не говорят даже самые опытные скриптеры!
Оценка: -----

#1
Пользователь офлайн   vawylon 

  • Знаток
  • Вставить ник
  • Раскрыть информацию
E_STREAMER_CUSTUM раскрываем потанцевал!

На примере возьмём систему домов.
Система домов записана в ассоциативный массив
#define MAX_HOUSES 1000
enum h_data{
h_handle, // id дома
h_pickup_enter, // пикап вход в дом
h_pickup_exit, // пикап выход из дома
h_x,// позиция пикапа 
h_y,// позиция пикапа 
h_z// позиция пикапа 
};
new house_data[MAX_HOUSE][h_data];



Возьмём штатную ситуацию: игрок подбирает пикап дома и мы как скриптеры начинаем проверять пикап вот таким способом

public OnPlayerPickUpDynamicPickup(playerid, pickupid)
{
		for(new i; i<MAX_HOUSE; i++)
		{
		    if(pickupid == house[i][h_pickup_enter])
		    {
		        printf("Номер дома: %d", house_data[i][h_handle]);
		        break;
		    }
		}
}



Если закинуть на тест вот такой код станет ясно, немного медленно...

public OnPlayerPickUpDynamicPickup(playerid, pickupid)
{
	new bool:isfind;
	new tick = GetTickCount();
	for(new loop; loop<10000; loop++)
	{
		for(new i; i<MAX_HOUSE; i++)
		{
			if(pickupid == house[i][h_pickup_enter])
			{
				isfind = true;
				break;
			}
		}
	}
	printf("IsFind: %d", isfind);
	printf("Tick count standart: %d", GetTickCount()-tick);
}



код выполнится 10.000 раз за 874 мл.сек - почти секунда!
IsFind: 1
Tick count standart: 874



И теперь перейдём к самой функции из за которой и затеялся данный карнавал!
Streamer_SetIntData(type, STREAMER_ALL_TAGS:id, data, value)
type - тип объекта (объект,пикап,актёр...)
STREAMER_TYPE_OBJECT (0)
STREAMER_TYPE_PICKUP (1)
STREAMER_TYPE_CP (2)
STREAMER_TYPE_RACE_CP (3)
STREAMER_TYPE_MAP_ICON (4)
STREAMER_TYPE_3D_TEXT_LABEL (5)
STREAMER_TYPE_AREA (6)
STREAMER_TYPE_ACTOR (7)

STREAMER_ALL_TAGS:id - id стримерского элемента.
data - "переменная" список стандартных
enum
{
	E_STREAMER_AREA_ID,
	E_STREAMER_ATTACHED_OBJECT,
	E_STREAMER_ATTACHED_PLAYER,
	E_STREAMER_ATTACHED_VEHICLE,
	E_STREAMER_ATTACH_OFFSET_X,
	E_STREAMER_ATTACH_OFFSET_Y,
	E_STREAMER_ATTACH_OFFSET_Z,
	E_STREAMER_ATTACH_R_X,
	E_STREAMER_ATTACH_R_Y,
	E_STREAMER_ATTACH_R_Z,
	E_STREAMER_ATTACH_X,
	E_STREAMER_ATTACH_Y,
	E_STREAMER_ATTACH_Z,
	E_STREAMER_COLOR,
	E_STREAMER_DRAW_DISTANCE,
	E_STREAMER_EXTRA_ID,
	E_STREAMER_HEALTH,
	E_STREAMER_INTERIOR_ID,
	E_STREAMER_INVULNERABLE,
	E_STREAMER_MAX_X,
	E_STREAMER_MAX_Y,
	E_STREAMER_MAX_Z,
	E_STREAMER_MIN_X,
	E_STREAMER_MIN_Y,
	E_STREAMER_MIN_Z,
	E_STREAMER_MODEL_ID,
	E_STREAMER_MOVE_R_X,
	E_STREAMER_MOVE_R_Y,
	E_STREAMER_MOVE_R_Z,
	E_STREAMER_MOVE_SPEED,
	E_STREAMER_MOVE_X,
	E_STREAMER_MOVE_Y,
	E_STREAMER_MOVE_Z,
	E_STREAMER_NEXT_X,
	E_STREAMER_NEXT_Y,
	E_STREAMER_NEXT_Z,
	E_STREAMER_PLAYER_ID,
	E_STREAMER_PRIORITY,
	E_STREAMER_ROTATION,
	E_STREAMER_R_X,
	E_STREAMER_R_Y,
	E_STREAMER_R_Z,
	E_STREAMER_SIZE,
	E_STREAMER_STREAM_DISTANCE,
	E_STREAMER_STYLE,
	E_STREAMER_SYNC_ROTATION,
	E_STREAMER_TEST_LOS,
	E_STREAMER_TYPE,
	E_STREAMER_WORLD_ID,
	E_STREAMER_X,
	E_STREAMER_Y,
	E_STREAMER_Z
}
Но мы будем использовать E_STREAMER_CUSTOM.

value - данные.


Так же можно использовать
native Streamer_GetFloatData(type, STREAMER_ALL_TAGS:id, data, &Float:result); // получить число с плавоющей точкой, Float тип
native Streamer_SetFloatData(type, STREAMER_ALL_TAGS:id, data, Float:value);  // установить число с плавоющей точкой, Float тип
native Streamer_GetIntData(type, STREAMER_ALL_TAGS:id, data);  // получить целое число
native Streamer_SetIntData(type, STREAMER_ALL_TAGS:id, data, value);  // установить целое число
native Streamer_RemoveIntData(type, STREAMER_ALL_TAGS:id, data);  // удалить "переменную"
native Streamer_HasIntData(type, STREAMER_ALL_TAGS:id, data); // существует ли что то в "переменной"
native Streamer_GetArrayData(type, STREAMER_ALL_TAGS:id, data, dest[], maxdest = sizeof dest); // получить массив
native Streamer_SetArrayData(type, STREAMER_ALL_TAGS:id, data, const src[], maxsrc = sizeof src); // записать массив
native Streamer_IsInArrayData(type, STREAMER_ALL_TAGS:id, data, value); // есть ли число в массиве
native Streamer_AppendArrayData(type, STREAMER_ALL_TAGS:id, data, value); //добавить данные в массив
native Streamer_RemoveArrayData(type, STREAMER_ALL_TAGS:id, data, value); // удалить значение value из массив
native Streamer_HasArrayData(type, STREAMER_ALL_TAGS:id, data); //существует ли массив
native Streamer_GetArrayDataLength(type, STREAMER_ALL_TAGS:id, data); //получить колличество элементов в массиве


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

#define CUSTUM_HOUSEID 0xFF
#define E_STREAMER_HOUSE_PICKUP_ENTER   E_STREAMER_CUSTOM(CUSTUM_HOUSEID)




Модернизируем наш код...

#define CUSTUM_HOUSEID 0xFF
#define E_STREAMER_HOUSE_PICKUP_ENTER   E_STREAMER_CUSTOM(CUSTUM_HOUSEID)
#define SetPickUpHouseHandle(%0,%1)            Streamer_SetIntData(STREAMER_TYPE_PICKUP, %0,  E_STREAMER_HOUSE_PICKUP_ENTER, %1)
#define GetPickUpHouseHandle(%0)               Streamer_GetIntData(STREAMER_TYPE_PICKUP, %0,  E_STREAMER_HOUSE_PICKUP_ENTER)
// STREAMER_TYPE_PICKUP - потому что мы работаем с пикапом;
/// SetPickUpHouseHandle(pickupid,value)
//.......
house[i][h_pickup_enter] = CreateDynamicPickup(1273, 2, house[i][h_x],house[i][h_y], house[i][h_z]);
SetPickUpHouseHandle(house[i][h_pickup_enter],i);
//.......
public OnPlayerPickUpDynamicPickup(playerid, pickupid)
{

	if(GetPickUpHouseHandle(pickupid) != 0) // примечание дома должны начинаться с 1, а не 0. 0 - не валидный дом!
	{
		printf("Номер дома: %d", GetPickUpHouseHandle(pickupid));
		return 1;
	}
}



Стример будет выбрасывать вот такое предупреждение
*** Streamer Plugin: Streamer_GetIntData: Invalid data specified.


Это будет означать, что переменная не существует.
Перед использованием E_STREAMER_CUSTOM рекомендуют проверять существует ли вообще такой адрес Streamer_HasIntData.
Я просто отключу данное сообщение с помощью функции Streamer_ToggleErrorCallback(true); в GameModeInit или OnFilterScriptInit().

При тестировании сразу поймём, почему стоит использовать E_STREAMER_CUSTOM
	new pickupid = house[998][h_pickup_enter];
	new = tick = GetTickCount();
	new bool:isfind;
	for(new loop; loop<10000; loop++)
	{
	    if(GetPickUpHouseHandle(pickupid) == 998)
	    {
	        isfind = true;
	    }
	}
	printf("IsFind: %d", isfind);
	printf("Tick count standart: %d", GetTickCount()-tick);


Результат
IsFind: 1
Tick count custom: 2


Самому не верится, что в 400 раз быстрее делаем выводы.


Если посмотреть мои работы, они очень сырые и возможно данная статья сырая, так как полного знания терминов адрес это или переменная, как назвать правильно - не знаю. Я с удовольствием прочитаю отзыв каждого из вас, внесу правки. Возможно данный способ уже все используют. Не общаюсь с про скриптерами, но пока примеров с данным функционалом не встречал.
Какой я вижу потанцевал в этом?
Потенциал огромен. По сути мы можем использовать динамическую память стримера которую предоставил Y_Lees очень легко и просто.
Мы можем дать возможность игрокам выбрасывать предметы создавать их как объект и эти объекты не придётся заносить в массив. А потом бегать по массиву и искать является ли он предметом или нет, что это за объект. В этот момент чувствую себя неандертальцем с палкой в руке. Объект - есть переменная.
Так же мы можем привязывать группу объектов к объекту (под объектом имею введу любой элемент стримера) и удалять их синхронно. Создавать пикапы из нескольких объектов(элементов) вносить правки и другое как сказал без массивов и циклов.

.....
        new Float:x, Float:y, Float:z, Float:distance;
        GetPlayerPos(playerid, x, y, z);
        new pickups[1];
        Streamer_GetAllVisibleItems(playerid, STREAMER_TYPE_PICKUP, pickups); // получаем список видимых пикапов сортируются по дистанции 0-самый ближайший. будем использовать самый ближайший хватит единичного размера
        if(GetPickUpHouseHandle(pickups[0]) != 0)
        {        
                Streamer_GetDistanceToItem(x,y,z, STREAMER_TYPE_PICKUP, pickups[0], distance, 3); // dimensions = 3 используем дистанцию по трём осям. можно убрать. стандарт - 3.
                if(distance < 3.0)
                {
                        printf("Рядом дом: %d", GetPickUpHouseHandle(pickups[0]));
                }
        }
}
.....



Теперь нам не придётся бегать по массиву и проверять каждый дом находится ли он рядом с игроком или нет. Мы просто получам ближайший пикап - читаем id дома и всё!
Считаю эта функция стала самым мощным обновлением стримера!

Копирование запрещено
Автор я: pawlo/vawylon

Сообщение отредактировал PAWLO: 15 мая 2022 - 16:47

3

#2
Пользователь офлайн   M I S T E V 

  • Эксперт
  • Вставить ник
  • Раскрыть информацию
Спасибо :yes:
0

#3
Пользователь офлайн   DeimoS 

  • Evil Scripter
  • Вставить ник
  • Раскрыть информацию
Ровно то же самое можно и просто через пикапы получить =) Так что поздравляю с открытием Америки
0

#4
Пользователь офлайн   vawylon 

  • Знаток
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияDeimoS (14 мая 2022 - 10:52) писал:

Ровно то же самое можно и просто через пикапы получить =) Так что поздравляю с открытием Америки

Каким образом? Можно пример?
0

#5
Пользователь офлайн   M I S T E V 

  • Эксперт
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияDeimoS (14 мая 2022 - 10:52) писал:

Ровно то же самое можно и просто через пикапы получить =) Так что поздравляю с открытием Америки

Если создавать сначала пикапы для недвижимости, бизнеса и т.п. использовав pickupid, а если нарушить такой порядок можно выйти за пределы массива. Или что-то другое имеешь ввиду?
0

#6
Пользователь офлайн   vawylon 

  • Знаток
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияM I S T E V (14 мая 2022 - 13:20) писал:

Если создавать сначала пикапы для недвижимости, бизнеса и т.п. использовав pickupid, а если нарушить такой порядок можно выйти за пределы массива. Или что-то другое имеешь ввиду?


Ты прав. Мой вариант исключает такую ошибку. Он отлично подходит к тем элементам которые удаляются и создаются не имеют порядка

Сообщение отредактировал PAWLO: 14 мая 2022 - 14:22

0

#7
Пользователь офлайн   continue 

  • Местный
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияM I S T E V (14 мая 2022 - 13:20) писал:

Если создавать сначала пикапы для недвижимости, бизнеса и т.п. использовав pickupid, а если нарушить такой порядок можно выйти за пределы массива. Или что-то другое имеешь ввиду?


Как? Можно создать 2 массива: ко одному обращение по pickupid (это будет основной), а второй по houseid, который возвращает pickupid для конкретного дома.
0

#8
Пользователь офлайн   vawylon 

  • Знаток
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияcontinue (14 мая 2022 - 18:09) писал:

Как? Можно создать 2 массива: ко одному обращение по pickupid (это будет основной), а второй по houseid, который возвращает pickupid для конкретного дома.


))))

а если у нас 2к пикапов нам нужно создавать массив с 2000 ячейками? Можно, но вдруг создастся пикап с id 2001 хана будет. Я уже молчу про объекты

Сообщение отредактировал PAWLO: 14 мая 2022 - 18:21

0

#9
Пользователь офлайн   DeimoS 

  • Evil Scripter
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияPAWLO (14 мая 2022 - 18:20) писал:

а если у нас 2к пикапов нам нужно создавать массив с 2000 ячейками?


Рассказываю по секрету: плагин, по сути своей, именно это и делает :)

Просмотр сообщенияPAWLO (14 мая 2022 - 18:20) писал:

но вдруг создастся пикап с id 2001 хана будет. Я уже молчу про объекты


Если у тебя в коде что-то происходит "вдруг" - ты не особо хороший программист :)


Просмотр сообщенияcontinue (14 мая 2022 - 18:09) писал:

Как? Можно создать 2 массива: ко одному обращение по pickupid (это будет основной), а второй по houseid, который возвращает pickupid для конкретного дома.


Можно и просто 2 массива на все системы пустить, рассчитав то, какое максимальное количество пикапов будет создаваться в моде: в первом хранить тип пикапа (бизнесы, дом и т.п.), а во втором уже ID бизнеса, дома и т.п.
Или даже обойтись одним, записывая только ID бизнесов/домов и т.п., но всячески модифицируя их значение, дабы оно было уникальным. Например, если у нас в моде может создаваться 1000 домов и 100 бизнесов, то бизнесы можно записывать как есть, а к ID домов прибавлять 1000 и уже для определения типа пикапа составить условие, а-ля:
new id = /*массив*/;
if(0 <= id <= MAX_BUSINESS)
{
    // Бизнес
}
else if(MAX_BUSINESS < id <= MAX_BUSINESS+MAX_HOUSE)
{
    // ДОМА
}

Конкретно пример выше не особо сопоставляется с тем алгоритмом, что я описал текстом, но суть, думаю, ясна.

Сообщение отредактировал DeimoS: 14 мая 2022 - 19:24

0

#10
Пользователь офлайн   continue 

  • Местный
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияPAWLO (14 мая 2022 - 18:20) писал:

))))

а если у нас 2к пикапов нам нужно создавать массив с 2000 ячейками? Можно, но вдруг создастся пикап с id 2001 хана будет. Я уже молчу про объекты


Только вот проблемка в том, что тебе стоит изучить как работает стример, а ещё зайти сюда. Больше чем там, создать сущностей в ЗОНЕ стрима нельзя.

Просмотр сообщенияDeimoS (14 мая 2022 - 19:14) писал:

Нажмите сюда, чтобы прочитать это сообщение. [Показать]



В случаи с массивом, там обращение должно быть за констатное время.

Сообщение отредактировал continue: 14 мая 2022 - 19:41

0

Поделиться темой:


  • (4 Страниц) +
  • 1
  • 2
  • 3
  • Последняя »
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

1 человек читают эту тему
0 пользователей, 1 гостей, 0 скрытых пользователей


Яндекс.Метрика