Быстрый перебор игроков в сети
Начну с предисловия.
Каждый раз, когда я захожу на форум, особенно в разделы вопросов или уроков, я натыкаюсь на подобные циклы
PHP код:
for (new i = 0; i < MAX_PLAYERS; i++)
или такие
PHP код:
for (new i = 0; i < GetMaxPlayers(); i++)
В такие моменты у меня рождается чувство, что такты процессора проюбываются зря впустую.
И поэтому я решил показать быстрый способ перебора игроков в сети, без лишних итераций цикла.
Как же он работает?
Теория. Attention: требуются знания и голова на плечах
Создаем один массив размером MAX_PLAYERS и переменную для подсчёта игроков, изначально равную нулю (предположим, players[MAX_PLAYERS] и num_players).
При запуске мода заполняем массив -1 и обнуляем num_players. Когда у нас подключается игрок, мы записываем его ид в массив, увеличивая num_players.
При отключении игрока, мы просто ставим ид последнего на положение ида отключившегося игрока.
В переборе мы просто вместо playerid используем players[i] и i<num_players.
Ну а теперь реализация кода.
К глобальным переменным добавляем:
PHP код:
new players[MAX_PLAYERS];
new num_players;
В public OnPlayerConnect:
PHP код:
players[num_players++] = playerid;
В public OnPlayerDisconnect:
PHP код:
for (new i = 0; i < num_players; i++)
{
if (players[i] == playerid)
{
players[i] = players[--num_players];
players[num_players] = -1;
break;
}
}
Вот и весь код.
Пример перебора игроков. Предположим у нас какой-нибудь ГФ-подобный мод, и нам надо отправить всем админам сообщение:
PHP код:
for (new i = 0; i < num_players; i++)
if(PlayerInfo[players[i]][pAdmin] > 0)
SendClientMessage(players[i], -1, "Прием");
Тест скорости
code
PHP код:
#include <a_samp>
#include "../include/foreach.inc"
new players[MAX_PLAYERS];
new num_players;
#define tforeach(%0) for(new _i, %0=players[_i]; _i <num_players; %0=players[++_i])
#define PROFILING_ITERS 10_000_000
main()
{
new time = 0;
//
printf("Tracker1's foreach test");
for (new i = 0; i < 125; i++)
players[num_players++] = i;
printf("125 players connected");
for (new i = 50; i < 75; i++)
{
for (new j = 0; j < num_players; j++)
{
if (players[j] == i)
{
players[j]=players[--num_players];
players[num_players] = -1;
break;
}
}
}
printf("50-74 IDs Disconnected");
printf("Starting main cycle "#PROFILING_ITERS" times");
time = GetTickCount();
for (new i = 0; i < PROFILING_ITERS; i++)
tforeach(x)
{
continue;
#pragma unused x
}
printf("Tracker1's foreach test DONE. Time: %d ms.",GetTickCount() - time);
//
print("\n");
//
printf("Y_Less's foreach test");
for (new i = 0; i < 125; i++)
Iter_Add(Player, i);
printf("125 players connected");
for (new i = 50; i < 75; i++)
Iter_Remove(Player, i);
printf("50-74 IDs Disconnected");
printf("Starting main cycle "#PROFILING_ITERS" times");
time = GetTickCount();
for (new i = 0; i < PROFILING_ITERS; i++)
foreach(new x:Player)
continue;
printf("Y_Less's foreach test DONE. Time: %d ms.",GetTickCount() - time);
//
print("\n");
return 1;
}
Без JIT:
Код:
Tracker1's foreach test
125 players connected
50-74 IDs Disconnected
Starting main cycle 10_000_000 times
Tracker1's foreach test DONE. Time: 27923 ms.
Y_Less's foreach test
125 players connected
50-74 IDs Disconnected
Starting main cycle 10_000_000 times
Y_Less's foreach test DONE. Time: 16611 ms.
С плагином JIT данная разработка быстрее чем Foreach.
Код:
Tracker1's foreach test
125 players connected
50-74 IDs Disconnected
Starting main cycle 10_000_000 times
Tracker1's foreach test DONE. Time: 2472 ms.
Y_Less's foreach test
125 players connected
50-74 IDs Disconnected
Starting main cycle 10_000_000 times
Y_Less's foreach test DONE. Time: 2723 ms.
Всё.
Update
Один быдлокодер любезно написал дефайн, чтобы было больше похоже на foreach от Y_Less.
PHP код:
^_^ Nicholas_West: #define tforeach(%0) for(new _i, %0=players[_i]; _i <num_players; %0=players[++_i])
С ним перебор выглядит вот так:
PHP код:
tforeach(x)
if (PlayerInfo[x][pAdmin]>0)
SendClientMessage(x,-1,"Прием");