Include dc_foreach_veh - швидкий перебір транспорту Архів - Pro Pawn - Портал про PAWN-скриптинг
Увага: Цей іклуд морально застарів. Аналогічний функціонал вже реалізований у foreach (https://github.com/Open-GTO/foreach), користуйтеся ним замість стороннього доповнення.
Старий вміст теми залишено з історичних причин.
Досить простий іклуд, що додає для foreach новий ітератор Vehicle, що містить у собі ID всіх транспортних засобів, що спали на сервері. Транспорт автоматично додається до ітератора під час створення (CreateVehicle/AddStaticVehicle(Ex)) і видаляється при знищенні (DestroyVehicle).
Для роботи инклуда потрібно foreach/y_iterate від Y_Less. Можете закинути їх як у папку "include" (у корені сервера), так і в "pawno/include", в інклуді враховуються обидва варіанти.
CMD:respawnvehicles(playerid, params[]) if (0 == IsPlayerAdmin(playerid)) return 0; foreach (new v: Vehicle) SetVehicleToRespawn(v); return SendClientMessage(playerid, -1, "Ви зареспавнили весь транспорт."); > ALTX:respawnvehicles("/resveh");
GetNearestVehicle(Float:x, Float:y, Float:z, Float:distance) new Float:t, nearest_veh_id = INVALID_VEHICLE_ID; foreach (new v:Vehicle) if (floatcmp((t = GetVehicleDistanceFromPoint(v, x, y, z)), distance) != 1) distance = t, nearest_veh_id = v; return nearest_veh_id; > GetNearestVehicleToPlayer(playerid, Float:distance) new Float:x, Float:y, Float:z; if (0 == GetPlayerPos(playerid, x, y, z)) return INVALID_VEHICLE_ID; return GetNearestVehicle(x, y, z, distance); >
Примітки: Не можна видаляти машини (DestroyVehicle) під час перебору ітератора Vehicle за допомогою foreach. Це пов'язано з тим, що видалення елементів з ітератора під час циклу за його елементами може призвести до непередбачуваних наслідків. Прикладкоду, який може призвести до фарбування:
foreach (v: Vehicle) DestroyVehicle(v);
Не намагайтеся в моді змінити значення макросу MAX_VEHICLES. Навіть якщо ви це значення зміните, скажімо, на 500, за допомогою CreateVehicle/AddStaticVehicle(Ex) все одно можна буде створити понад 500 машин. Приклади втручання в MAX_VEHICLES (краще приберіть їх зі свого скрипта):
#undef MAX_VEHICLES #define MAX_VEHICLES 500
#if defined MAX_VEHICLES #undef MAX_VEHICLES #endif #define MAX_VEHICLES 500
#if defined MAX_VEHICLES #undef MAX_VEHICLES #endif enum < MAX_VEHICLES = 500 >;
Інклуд працює тільки в тому скрипті, в якому створюється та видаляється весь транспорт на сервері. Тобто. якщо ви використовуєте инклуд в моді, те й створювати/видаляти транспорт теж слід із мода, а чи не з фильтрскоиптов, т.к. неможливо відстежити створення та видалення транспорту з іншого скрипту.
Автор: Daniel_Cortez (http://pro-pawn.ru/member.php?100-Daniel_Cortez)
Сильно відрізняється в швидкодії від цього. 80-%D0%BC%D0%B0%D1%88%D0%B8%D0%BD-%D0%BF%D0%BE-%D0%BF%D1%80%D0%B8%D0%BD%D1 %86%D0%B8%D0%BF%D1%83-foreach&highlight=foreach+%D1%82%D1%80%D0%B0%D0%BD%D1%81%D 0%BF%D0%BE% D1%80%D1%82) варіанти?
UPD:Якщо ви не оновлювали include a_vehicles.inc до версії 0.3.7, можуть з'явитися warning's з приводу addsiren.Щоб це виправити, оновіть ваші include's.
Я провів кілька тестів, регулюючи кількість обертів у циклах профайлера і кількість машин на сервері. Для кількості машин брали значення MAX_VEHICLES, MAX_VEHICLES/8 (=250) і 0.
#if !defined IsValidVehicle native IsValidVehicle(vehicleid); #endif
#define forveh(%0) for(new ouf, %0=forveh_vehicles[ouf]; ouf #include #define GetTickCount() tickcount() #endif
main() new t1, t2, i, j; #emit zero.pri #emit lctrl 7 #emit stor.s.pri i printf( "Тестування: vs " LINE_BREAK, code_snippets_names[0], code_snippets_names [1] ); static const JIT_status_strings[2][] = ; printf( "Режим: %s, %dx%d ітерацій.\a" LINE_BREAK, JIT_status_strings[i], PROFILE_ITERATIONS_MAJOR, PROFILE_ITERATIONS_MINOR ); Prerequisites(); for (i = 0; i vs Режим: інтерпретований, 10000x10 ітерацій. Кількість транспорту: 2000. forveh(c): 9125 foreach(v:Vehicle): 5383
Тестування: vs Режим: інтерпретований, 100000x10 ітерацій. Кількість транспорту: 250. forveh(c): 11461 foreach(v:Vehicle): 6750
Тестування: vs Режим: інтерпретований, 10000000x10 ітерацій. Кількість транспорту: 0. forveh(c): 7564 foreach(v:Vehicle): 6757
Тестування: vs Режим: з JIT-компіляцією, 100000x10 ітерацій. Кількість транспорту: 2000. forveh(c): 8122 foreach(v:Vehicle): 8995
Тестування: vs Режим: з JIT-компіляцією, 1000000x10 ітерацій. Кількість транспорту: 250. forveh(c): 10918 foreach(v:Vehicle): 11330
Тестування: vs Режим: з JIT-компіляцією, 100000000x10 ітерацій. Кількість транспорту: 0. forveh(c): 12985 foreach(v:Vehicle): 11423
Варіант з foreach майже в 2 рази випереджає forveh, а з використанням JIT лише злегка поступається (і то не у всіх ситуаціях: якщо машин мало, foreach обганяє forveh навіть з JIT). До того ж, forveh підходить тільки для перебору машин, а foreach - більш універсальний варіант. Також хотілося б помітити, що в forveh(v) всередині циклу створюється локальна змінна v,Час, як у foreach можна використовувати вже існуючу, щоб не витрачався час на створення нової локальної змінної - саме так я і вчинив у тесті.