Форум Pawn.Wiki - Воплоти мечту в реальность!: Итератор (Вместо инклюда foreach) - Форум Pawn.Wiki - Воплоти мечту в реальность!

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

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

[ INC ][ All ]
Итератор (Вместо инклюда foreach)
Оценка: -----

#1
Пользователь офлайн   Coco = 10g; 

  • Новичок
  • Вставить ник
  • Раскрыть информацию
Привет всем, написал свой типа итератор, мне не нравился инклюд foreach, ведь там в итератор добавляються игроки при OnPlayerConnect, а если игрок зашёл на сервер, а потом вышел не успев авторизоваться, то серверу придёться сделать лишнии движения, записать ID игрока в итератор, а потом заместить/убрать/удалить, поэтому я написал свой итератор. Что бы добавить новый ID игрока в итератор, нужно его вызвать и передать в него новый playerid, допустим у меня, функция вызываеться внутри функции авторизации, так же функция авторизации ( не путать с функцией итератора ) вызываеться после регистрации игрока, так вот эту функцию итератора ( что бы записать новый ID игрока в итератор ) можно вызвать как раз внутри функции авторизации. Тогда итерация произойдёт ровно в тот момент, когда игрок введёт свой пароль, и заспавниться, только тогда ему будут приходить какие либо сообщения по типу тех-же объявлений ([Реклама US]) как на тринити.



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.


Я очень плохо объясняю, я не знаю поймёте ли вы что тут вообще происходит) Но на крайняк просто возьмите готовые функции и используйте по полной, если вы достаточно опытный разработчик, расскажите пожалуйста новичкам чё тут происходит, Спасибо!

0

#2
Пользователь офлайн   21th year 

  • Профессионал
  • Вставить ник
  • Раскрыть информацию
Такая разница при выходе (пару миллисекунд максимум) не сделают ничего критичного. А у тебя по сути, это просто работа с массивами и аналог аля, игрок авторизовался
0

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

  • Эксперт
  • Вставить ник
  • Раскрыть информацию
Я правильно понял, ты вместо того, чтобы найти директиву #define FOREACH_I_Player в include foreach и указать 0, чтобы при подключении и отключении игрока его не добавляло и не удаляло из итератора Player, решил сделать это?

Можно создать свой итератор типа LoginPlayers и сделать, то, что тебе необходимо было.

Сообщение отредактировал Saibot: 07 января 2025 - 18:56

1

#4
Пользователь офлайн   Coco = 10g; 

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

Просмотр сообщенияSaibot (07 января 2025 - 18:55) писал:

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


Так я именно это и сделал, форич содержит ещё всякого в себе, лишнее и не нужное, если тебе нужен только Итератор
0

#5
Пользователь офлайн   MuthaX 

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

Просмотр сообщенияCoco = 10g; (07 января 2025 - 18:19) писал:

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;
}

Угробил всю выгоду в читаемости и произвоидительности каким-то playersList[i] - нет бы в переменную записать. Знаешь сколько там кода нагенерирует ванильный компилятор? А он то не особо в оптимизацию может. Непонятно зачем тут проверка на интерьер при имеющейся проверке виртуального мира, читер/багоюзер знающий про такую особенность мог бы воспользоваться этим для сокрытия своих разговоров от нежелательных лиц. Порядок условий тоже вызывает пару вопросов и проверка на дальность могла бы предваряться проверкой на стрим.




Просмотр сообщенияCoco = 10g; (07 января 2025 - 18:19) писал:

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--;
}


А тут вообще подмена понятий в аргументах твоих функций: playerid - у тебя фактически номер в списке, а не сам номер игрока.
0

#6
Пользователь офлайн   Coco = 10g; 

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

Просмотр сообщения21th year (07 января 2025 - 18:34) писал:

Такая разница при выходе (пару миллисекунд максимум) не сделают ничего критичного. А у тебя по сути, это просто работа с массивами и аналог аля, игрок авторизовался


Работа с массивами, а форич разве не "работа с массивами" или зачем ты это вообще упомянул? Если разницы нет, и это не "аля игрок авторизовался", это вообще про итератор, он был написан только ради, того что бы самому понять как это работает, а не использовать готовое решение, да и готовое решение содержит в себе много лишнего, а мне нужен только итератор.
0

#7
Пользователь офлайн   Coco = 10g; 

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

Просмотр сообщенияMuthaX (07 января 2025 - 19:31) писал:

Угробил всю выгоду в читаемости и произвоидительности каким-то playersList[i] - нет бы в переменную записать.


Каким образом мне избавиться от playerList[i]? И о какой функции стримера ты говоришь?
0

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

  • Знаток
  • Вставить ник
  • Раскрыть информацию
А создать итератор под логин что мешает?
0

#9
Пользователь офлайн   Coco = 10g; 

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

Просмотр сообщенияtommyled (07 января 2025 - 22:09) писал:

А создать итератор под логин что мешает?


Ты о чём?
0

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

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

Просмотр сообщенияtommyled (07 января 2025 - 22:09) писал:

А создать итератор под логин что мешает?


Религия, очевидно
0

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


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

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


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