Disclamer
По ходу статьи, или как эта тема называеться, я буду путаться и писать вместо "программа", что то типа "мы"/"код".
Да, можно сказать что будет много воды, но скорей я просто буду очень много разжёвывать.
Если что-то не понятно, просто берите и пользуйтесь, если уж сильно хотите понять, то разбирайте сами код.
Ко всем глобалкам, playersList будет поочереди хранить все ID игроков которые авторизованы на сервере.
playersNumberInTheList в котором каждая ячейка будет ID игрока, то есть при обращении к массиву вот так playersNumberInTheList[5] мы будем обращаться к ячейки которая принадлежит игроку с ID 5,
И получать из неё очередь ID игрока из playersList.
Ну и самое простое, это playersOnline, тут мы просто прибавляем по одному каждую авторизацию игрока, или вычитание когда игрок покидает сервер, и таким образом playersOnline хранит в себе количество авторизованных игроков.
new playersList[MAX_PLAYERS], playersNumberInTheList[MAX_PLAYERS], playersOnline;
Теперь про функции, первая функция это сам итератор, тут всё просто, в playersList по очереди playersOnline записываем playerid то есть ID игрока, первый в списке при подключении будет 0, потом 1, потом 2, и т.д.
В playerNumberInTheList в ячейку по ID игрока записываем в какой ячейке будет находиться вновь авторизовавшийся игрок.
Ну и собственно инкрементируем playerOnline что бы следующий игрок (если в этот раз был с ID = 0) был записан в ячейку 1 в playerList и в ячейку с ID 1 был записан номер ячейки в playersNumberInTheList из playerList
stock IteratePlayer(playerid) { playersList[playersOnline] = playerid; playersNumberInTheList[playerid] = playersOnline; playersOnline++; }
Теперь про самый сложный ( на этапе разработки ) для меня сток, было трудно придти к тому что бы это заработало как надо.
Что у вас тут происходитбл.... Если авторизованный игрок покидает сервер, мы получаем его ID из OnPlayerDisconnect ( именно оттуда этот сток {RemoveIteratePlayer} и вызываеться ),
То код начинает выполнять следующии манипуляции: 1. Создаёт цил, а так же переменную i которая будет хранить в себе номер ячейки ( из списка playersList, потому что playersNumberInTheList как мы помним, по ID игрока хранит в себе номер ячейки где на данный момент находиться ID игрока из playersList ),
Далее код проверяет ( я понимаю что проверяет не код, а программа, но мне так удобней выражаться ) i < playersOnline, меньше ли очередь ( очередь храниться в i ) игрока относительно количества игроков в онлайне,
происходит это для того что бы сместить ID-шники игроков ровно столько раз сколько максимально игроков на сервере минус очередь ID-шника игрока в списке playersList, допустим на сервере 5 игроков,
все ID игроков храняться в списке таким образом ( в хоотичном порядке так как игроки заходили/выходили, и делали это не поочерёдно ) playersList[0] = 0, playersList[1] = 1 playersList[2] = 4 playersList[3] = 2 playersList[4] = 3, таким образом если вышел игрок с ID 4, то мы получим из playersNumberInTheList[4] номер ячейки [2], записываем в [/b]i[/b] эту 2, проверяем, 2 < 5 ( да, меньше) поэтому переходим выполняем код внутри for), далее идёт playerNumberInTheList[playersList[i]] -= 1.
Происходит тут следующее, получаем playersList[i] то есть ID игрока который вышел, из ячейки 2, так как ID 4 храниться в ячейки playersList[2], поэтому наша i хранит в себе 2, следующим шагом обращаемся по ID игрока к playersNumberInTheList[playersList[i]] так как playersList[i] вернуло нам 4 ( да, playersList[i] нам ничего не возвращало, мы просто вычислили что за значение храниться в playersList[i], но мне так удобней выражаться ), таким образом, грубо говоря, обращение происходит к playersNumberInTheList[2], в котором храниться номер ячейки из playersList, которая принадлежит ID 4, в нашем примере это ячейка 2 из playersList. -= 1 таким образом мы смещаем очередь внутри ячеек ( ячейки как мы помним используються как ID игроков ), то есть в нашем случае игрок с ID 4 покинул сервер, мы узнали что номер ячейки из playersList[2] равно 4, мы смещаем очередь назад на еденицу, таким образом playersNumberInTheList[4] хранило = 2 ( 2 это очередь начинающаяся с 0 в списке playerList ), а сейчас будет хранить 1, то есть следующии (playersNumberInTheList[2] хранящее 3 ( которые нам уже важны ) так же сместяться на -1, и станет 2, получается будет уже не в третьей ячейке как было ( 4-ой очередью ) в списке, а уже вторым ( 3-ей в очереди ).
Следующим делом идёт строка с playersList[i] = playersList[i+1], тут всё просто смещаем на один начиная с того ID в очереди который вышел, допустим вышел игрок с ID 4 тот-же самый, playersList[i] хранит в себе 2, так как игрок с ID 4 был в ячейке 2 ( третьем в очереди ) по списку в playersList, мы записываем в playersList[2] следующий ID игрока по списку, playersList[2+1=3] то есть playersList[3], там у нас как мы помним храниться 2, смещаем вместо 4 и записываем 2, и так далее пока не дойдём до playersOnline.
stock RemoveIteratePlayer(playerid) { for(new i = playersNumberInTheList[playerid]; i < playersOnline; i++) { playersNumberInTheList[playersList[i]] -= 1; playersList[i] = playersList[i+1]; } playersOnline--; }
Ещё что важно, при выходе игрока с сервера, то есть в OnPlayerDisconnect когда мы вызываем в нём функцию RemoveIteratePlayer(playerid), рекомендуеться проверять, был ли игрок с таким ID ( id игрока который покинул сервер ) залогинен, ну или как вы назовёте, авторизован.
Выглядит это примерно так.
public OnPlayerDisconnect(playerid, reason) { if(player_temp[playerid][p_online]) RemoveIteratePlayer(playerid); }
Только вам нужно указать вместо player_temp[playerid][p_online] свой массив и переменную, что бы узнать залогинен ли был игрок. Вы можете использовать это где удобно, в том же ProxDetecrtor, вот пример.
stock ProxDetector(Float:radius, playerid, const message[], color) { new playerVirtualWorld, playerInterior, Float:X, Float:Y, Float:Z; GetPlayerPos(playerid, X, Y, Z); playerVirtualWorld = GetPlayerVirtualWorld(playerid); playerInterior = GetPlayerInterior(playerid); for(new i = 0; i < playersOnline; i++) { if(!IsPlayerInRangeOfPoint(playersList[i], radius, X, Y, Z)) continue; if(GetPlayerVirtualWorld(playersList[i]) != playerVirtualWorld) continue; if(GetPlayerInterior(playersList[i]) != playerInterior) continue; SendClientMessage(playersList[i], color, message); } return true; }
Точно так же вы можете адаптировать новый итератор для админов, вот все строки для этого.
new adminsList[MAX_PLAYERS], adminsNumberInTheList[MAX_PLAYERS], adminsOnline; stock IterateAdmin(playerid) { adminsList[adminsOnline] = playerid; adminsNumberInTheList[playerid] = adminsOnline; adminsOnline++; } stock RemoveIterateAdmin(playerid) { for(new i = adminsNumberInTheList[playerid]; i < adminsOnline; i++) { adminsNumberInTheList[adminsList[i]] -= 1; adminsList[i] = adminsList[i+1]; } adminsOnline--; }
Так же при авторизации игрока можно проверять, имееться ли админ уровень у игрока, что-то типа player_temp[playerid][p_admin_level],
Всё в той же функции которая вызываеться после авторизации игрока.
if(player_temp[playerid][p_admin_level]) IterateAdmin(playerid);
А так если у вас авторизация в админ панель по паролю, то вызывайте уже IterateAdmin после успешной авторизации. Ну и при дисконекте, или разлогинивании точно так же удаляйте игрока с итератора админов.
if(player_temp[playerid][p_online]) { RemoveIteratePlayer(playerid); RemoveIterateAdmin(playerid); }
А если же у вас админка через панель, то есть отдельная авторизация по паролю допустим, то уже проверяйте перед удалением, был ли игрок вообще авторизован в админ панель, что-то типа...
if(player_temp[playerid][p_online]) { RemoveIteratePlayer(playerid); if(player_temp[playerid][p_admin_login] RemoveIterateAdmin(playerid); }
Не забывайте что эти проверки ( if ифы ) происходят в OnPlayerDisconnect.
Я очень плохо объясняю, я не знаю поймёте ли вы что тут вообще происходит) Но на крайняк просто возьмите готовые функции и используйте по полной, если вы достаточно опытный разработчик, расскажите пожалуйста новичкам чё тут происходит, Спасибо!