PDA

Просмотр полной версии : [Мануал] Ограничение времени на регистрацию/авторизацию



L0ndl3m
01.11.2013, 00:28
Думаю у многих есть такое: Если игрок в течении нескольких секунд не вводит пароль, то его кикает с сервера, и используют таймер для игрока. Сейчас я покажу пример как можно сделать практически то же самое.


В начало скрипта:


new
player_kick_time[MAX_PLAYERS char];

В OnPlayerConnect:

player_kick_time{playerid} = 30;

Думаю у каждого есть односекундный глобальный таймер, если нет, то создадим его.

В OnGameModeInit:

SetTimer("@__login_timer", 1000, 1);

Далее создадим паблик (если у вас есть односекундный паблик, то его создавать не нужно):


@__login_timer();
@__login_timer() {
for (new i = GetPlayerPoolSize() + 1; --i >= 0;) {
if (IsPlayerConnected(i)
&& player_kick_time{i} != 0
&& --player_kick_time{i} == 0) {
SendClientMessage(i, -1, "Время на регистрацию / авторизацию закончилось, вы кикнуты.");
Kick(i);
}
}
}


И после того как игрок вошёл в аккаунт / зарегистрировался:

player_kick_time{playerid} = 0;


В OnPlayerConnect:


SetPVarInt(playerid, "player_kick_time", GetTickCount() + 15000);

В конец мода, всё тот-же паблик ( если у вас есть односекундный таймер, его создавать не нужно ):


@__login_timer();
@__login_timer() {
new
tick = GetTickCount();

for (new i = GetPlayerPoolSize() + 1; --i >= 0;) {
if (IsPlayerConnected(i)
&& GetPVarInt(i, "player_kick_time") != 0
&& GetPVarInt(i, "player_kick_time") < tick) {
SendClientMessage(i, -1, "Время на регистрацию / авторизацию закончилось, вы кикнуты.");
Kick(i);
}
}
}


Теперь после того, как игрок зарегистрировался / вошёл в аккаунт:


DeletePVar(playerid, "player_kick_time");



Автор: L0ndl3m (http://pro-pawn.ru/member.php?2057-L0ndl3m)

Специально для: Pro-Pawn.Ru (http://pro-pawn.ru)

Копирование данной статьи без разрешения автора запрещено!

#Vito
01.11.2013, 00:33
Понравилось :3

Osetin
01.11.2013, 11:11
Неплохо, молодец..

Salvacore
01.11.2013, 16:15
Уже стоит:)

fleimos
02.11.2013, 01:03
неплохо

Ra4ok
02.11.2013, 01:16
Давно искал

Wilso[N]
02.11.2013, 21:18
Норм, Пригодилось)

ImpreZa177
08.04.2015, 19:35
Eror 017: undefined symbol @__loginTimer ЧТО ДЕЛАТЬ? HELP!!!!

L0ndl3m
08.04.2015, 20:03
Eror 017: undefined symbol @__loginTimer ЧТО ДЕЛАТЬ? HELP!!!!
Если делать всё по мануалу, то ошибок не должно быть.

Valera_Trefilov
09.04.2015, 14:55
Я бы сделал так:



public OnPlayerConnect(playerid)
{
SetPVarInt(playerid,"Loginned",1);
SetTimerEx("LoginnedTimer", 60000, 0, "i", playerid);
return true;
}




forward LoginnedTimer(i);
public LoginnedTimer(i)
{
if(GetPVarInt(i,"Loginned")==1)
Kick(i);
return true;
}

это туда где вы авторизуетесь:

if(GetPVarInt(playerid,"Loginned")==1) DeletePVar(playerid,"Loginned");

wAx
09.04.2015, 19:54
Я бы сделал так:



public OnPlayerConnect(playerid)
{
SetPVarInt(playerid,"Loginned",1);
SetTimerEx("LoginnedTimer", 60000, 0, "i", playerid);
return true;
}




forward LoginnedTimer(i);
public LoginnedTimer(i)
{
if(GetPVarInt(i,"Loginned")==1)
Kick(i);
return true;
}

это туда где вы авторизуетесь:

if(GetPVarInt(playerid,"Loginned")==1) DeletePVar(playerid,"Loginned");

А если я зайду, увижу окно авторизации, продержусь 50 секунд, выйду и следом зайдет игрок под моим ID

Valera_Trefilov
09.04.2015, 21:48
А если я зайду, увижу окно авторизации, продержусь 50 секунд, выйду и следом зайдет игрок под моим ID

Не будет такого. Запуск таймера в коннекте.

Разве что можно делать так:



public OnPlayerConnect(playerid)
{
SetPVarInt(playerid,"Loginned",SetTimerEx("LoginnedTimer", 60000, 0, "i", playerid));
return true;
}



public OnPlayerDisconnect(playerid,reason)
{
if(GetPVarInt(playerid,"Loginned")!=0)
KillTimer(GetPVarInt(playerid,"Loginned"));
return true;
}



forward LoginnedTimer(i);
public LoginnedTimer(i)
{
if(GetPVarInt(i,"Loginned")!=0)
Kick(i);
return true;
}


это туда где вы авторизуетесь:


if(GetPVarInt(playerid,"Loginned")!=0) DeletePVar(playerid,"Loginned");

исправил в общем

wAx
10.04.2015, 17:53
Не будет такого. Запуск таймера в коннекте.

Это и являлось причиной ошибки.

L0ndl3m
10.04.2015, 18:23
Много кто предлагал делать, но: Зачем создавать для каждого игрока таймер? Если можно проверять каждого игрока в цикле, что более надёжнее, нежели проверять определённого.

Maranzalla
12.04.2015, 22:18
Я бы сделал так:



public OnPlayerConnect(playerid)
{
SetPVarInt(playerid,"Loginned",1);
SetTimerEx("LoginnedTimer", 60000, 0, "i", playerid);
return true;
}




forward LoginnedTimer(i);
public LoginnedTimer(i)
{
if(GetPVarInt(i,"Loginned")==1)
Kick(i);
return true;
}

это туда где вы авторизуетесь:

if(GetPVarInt(playerid,"Loginned")==1) DeletePVar(playerid,"Loginned");

да этот вариант лучше

Coopr
24.04.2016, 22:38
Извини никто не скажет как добавить чтобы в чат писалось время это. К примеру:
Оставшее время на авторизацию : 30(--30-29-28-27-26-25-24-23-22-21-20.....)
С убыванием на -1 и как ноль то Кик

wAx
25.04.2016, 09:55
Извини никто не скажет как добавить чтобы в чат писалось время это. К примеру:
Оставшее время на авторизацию : 30(--30-29-28-27-26-25-24-23-22-21-20.....)
С убыванием на -1 и как ноль то Кик

выводить в чат каждую секунду время оставшееся на авторизацию - бредовая затея, не думаю что игрокам понравится. Но если все таки хочешь, то создаешь переменную, равную общему времени на авторизацию и в секундном таймере вычитаешь по 1 секунде, обновляешь данные и выводишь игроку в чат.

DeimoS
25.04.2016, 10:31
выводить в чат каждую секунду время оставшееся на авторизацию - бредовая затея, не думаю что игрокам понравится. Но если все таки хочешь, то создаешь переменную, равную общему времени на авторизацию и в секундном таймере вычитаешь по 1 секунде, обновляешь данные и выводишь игроку в чат.

Ну или без переменной:

SetTimerEx("@____TimeForAuthorization", 1000, 0, "ii", playerid, 30);

@____TimeForAuthorization(playerid, time);
@____TimeForAuthorization(playerid, time)
{
new string[...];
format(...);
SendClientMessage(playerid, -1, string);
if(time > 0) SetTimerEx("@____TimeForAuthorization", 1000, 0, "ii", playerid, time-1);
else
{
SendCLientMessage(playerid. -1. "Время вышло");
}
return 1;
}
Я не говорю, что этот вариант лучше или оптимизированнее - я не тестировал. Просто ещё один вариант реализации, который мне пришёл на ум

Coopr
25.04.2016, 10:34
new string[30];
format(string, sizeof(string), "%d", --string);
Так??
:blush2:

- - - Добавлено - - -


Ну или без переменной:

SetTimerEx("@____TimeForAuthorization", 1000, 0, "ii", playerid, 30);

@____TimeForAuthorization(playerid, time);
@____TimeForAuthorization(playerid, time)
{
new string[...];
format(...);
SendClientMessage(playerid, -1, string);
if(time > 0) SetTimerEx("@____TimeForAuthorization", 1000, 0, "ii", playerid, time-1);
else
{
SendCLientMessage(playerid. -1. "Время вышло");
}
return 1;
}
Я не говорю, что этот вариант лучше или оптимизированнее - я не тестировал. Просто ещё один вариант реализации, который мне пришёл на ум

Получается к все этому мне надо сделать еще так???

DeimoS
25.04.2016, 10:40
new string[30];
format(string, sizeof(string), "%d", --string);
Так??
:blush2:

Нет :D Если брать мою реализацию, то так:

@____TimeForAuthorization(playerid, time);
@____TimeForAuthorization(playerid, time)
{
new string[3];
format(string, sizeof(string), "%d", time);
SendClientMessage(playerid, -1, string);
if(time > 0) SetTimerEx("@____TimeForAuthorization", 1000, 0, "ii", playerid, time-1);
else
{
SendCLientMessage(playerid. -1. "Время вышло");
}
return 1;
}
Если брать реализацию wAx, то можно при начале авторизации присвоить к pVar значение, например:

SetPVarInt(playerid, "TimeForAuthorization", 31);
И потом в секундный таймер вставить код, типа:

if(GetPVarInt(playerid, "TimeForAuthorization"))
{
new authorization_time = GetPVarInt(playerid, "TimeForAuthorization")-1;

SetPVarInt(playerid, "TimeForAuthorization", authorization_time);
if(authorization_time == 1)
{
SendClientMessage(playerid, -1, "Время вышло");
DeletePVar(playerid, "TimeForAuthorization");
}
else
{
new string[3];
format(string, sizeof(string), "%d", authorization_time-1);
SendClientMessage(playerid, -1, string);
}
}
Только playerid на переменную цикла заменить нужно

SliM
25.04.2016, 10:42
OnPlayerConnect (playerid)
{
SetTimerEx ("PlayerEnterPassword", 0, 1000, "ii", playerid, 60);//60 = 1 min
}
OnPlayerLogin (playerid)
{
SetPvarInt (playerid, "enter_password", true);
}
PlayerEnterPassword (playerid, time)
{
if (GetPvarInt (playerid, "enter_password"))
{
DeletePVar (playerid, "enter_password");
GameTextForPlayer (playerid, "~g~password ok", 3000, 4);
return 1;
}
if (!time)
{
SendClientMessage (playerid, -1, "слишком медленно");
Kick (playerid);
return 1;
}
SetTimerEx ("PlayerEnterPassword", 0, 1000, "ii", playerid, -- time);
new
show_time [18]
;
format (show_time, sizeof show_time, "Time to Kick: %i", time);
GameTextForPlayer (playerid, show_time, 1000, 4);
}
псевдокод

Coopr
25.04.2016, 10:51
new
player_kick_time[MAX_PLAYERS char];

В OnPlayerConnect:

player_kick_time{playerid} = 30; // Отсчёт на 30 секунд

Думаю у каждого есть односекундный глобальный таймер, если нет, то создадим его.

В OnGameModeInit:

SetTimer("@__login_timer", 1000, 1); // Глобальный таймер на 1 секунду

Далее создадим паблик (если у вас есть односекундный паблик, то его создавать не нужно):


@__login_timer();
@__login_timer()
{
new
i = GetMaxPlayers();

do
{
--i;
if(IsPlayerConnected(i) && player_kick_time{i} != 0 && --player_kick_time{i} == 0)
{
SendClientMessage(i, -1, "Время на регистрацию / авторизацию закончилось, вы кикнуты");
Kick(i);
}
}
while(i);
}


И после того как игрок вошёл в аккаунт / зарегистрировался:

player_kick_time{playerid} = 0;


@____TimeForAuthorization(playerid, time);
@____TimeForAuthorization(playerid, time)
{
new string[3];
format(string, sizeof(string), "%d", time);
SendClientMessage(playerid, -1, string);
if(time > 0) SetTimerEx("@____TimeForAuthorization", 1000, 0, "ii", playerid, time-1);
else
{
SendCLientMessage(playerid. -1. "Время вышло");
}
return 1;
}




У меня код будет выглядить так??

DeimoS
25.04.2016, 12:05
new
player_kick_time[MAX_PLAYERS char];

В OnPlayerConnect:

player_kick_time{playerid} = 30; // Отсчёт на 30 секунд

Думаю у каждого есть односекундный глобальный таймер, если нет, то создадим его.

В OnGameModeInit:

SetTimer("@__login_timer", 1000, 1); // Глобальный таймер на 1 секунду

Далее создадим паблик (если у вас есть односекундный паблик, то его создавать не нужно):


@__login_timer();
@__login_timer()
{
new
i = GetMaxPlayers();

do
{
--i;
if(IsPlayerConnected(i) && player_kick_time{i} != 0 && --player_kick_time{i} == 0)
{
SendClientMessage(i, -1, "Время на регистрацию / авторизацию закончилось, вы кикнуты");
Kick(i);
}
}
while(i);
}


И после того как игрок вошёл в аккаунт / зарегистрировался:

player_kick_time{playerid} = 0;


@____TimeForAuthorization(playerid, time);
@____TimeForAuthorization(playerid, time)
{
new string[3];
format(string, sizeof(string), "%d", time);
SendClientMessage(playerid, -1, string);
if(time > 0) SetTimerEx("@____TimeForAuthorization", 1000, 0, "ii", playerid, time-1);
else
{
SendCLientMessage(playerid. -1. "Время вышло");
}
return 1;
}




У меня код будет выглядить так??

Зачем массив? Тем более если ты используешь мой первый метод...
Я уже дал же готовый код для обоих случаев. Не нужно ничего додумывать там. Просто добавь удаление таймера/pVar после авторизации или выхода

$continue$
25.04.2016, 22:45
Дуймсос, а Вы мазохист инициализировать переменную при каждом такте таймера.

Prolific
25.04.2016, 22:48
Что за мода пошла поднимать темы 13 года и вместо наглядной конструкции forward,public использовать @.

Profyan
26.04.2016, 13:22
Что за мода пошла поднимать темы 13 года и вместо наглядной конструкции forward,public использовать @.

Про @: видимо скриптеры получают от этого какой-то кайф,думая,что открыли неизведанные возможности.

Nurick
26.04.2016, 13:39
Про @: видимо скриптеры получают от этого какой-то кайф,думая,что открыли неизведанные возможности.

Каждый сам выбирает как будет состоять строение кода его, это же не влияет на работу кода!

Nurick
26.04.2016, 14:58
По теме:
Я думаю лучше будет использовать тут TextDrawSetString и совместить это с предложенным вариантом "DeimoS"


forward SecondTimer();


new Text:time_limit[2];


SetTimer("SecondTimer", 1000, 1);


public SecondTimer()
{
for(new i = 0; i < MAX_PLAYERS; i++)
{
if(GetPVarInt(i, "time_limit_for_authorization"))
{
SetPVarInt(i, "time_limit_for_authorization", GetPVarInt(i, "time_limit_for_authorization") - 1);
if(GetPVarInt(i, "time_limit_for_authorization") - 1 == 1)
{
SendClientMessage(i, -1, "Время на авторизацию истекло");
SendClientMessage(i, 0xFFCC00FF, "Введите \"/q\" (/quit) для выхода");
TextDrawHideForPlayer(i, time_limit[0]);
TextDrawHideForPlayer(i, time_limit[1]);
DeletePVar(i, "time_limit_for_authorization");
_DelayedKick(i);
}
else
{
new string[9];
format(string, sizeof(string), "Kick: %d", GetPVarInt(i, "time_limit_for_authorization") - 1);
TextDrawSetString(time_limit[1], string);
TextDrawShowForPlayer(i, time_limit[0]);
TextDrawShowForPlayer(i, time_limit[1]);
}
}
}
}

Когда игрок авторизуется:

SetPVarInt(playerid, "time_limit_for_authorization", 31);

Вошел/авторизовался:

DeletePVar(playerid, "time_limit_for_authorization");
TextDrawHideForPlayer(playerid, time_limit[0]);
TextDrawHideForPlayer(playerid, time_limit[1]);


time_limit[0] = TextDrawCreate(153.250000, 209.166656, "_");
TextDrawLetterSize(time_limit[0], 0.000000, 2.924074);
TextDrawTextSize(time_limit[0], 38.625000, 0.000000);
TextDrawUseBox(time_limit[0], 1);
TextDrawBoxColor(time_limit[0], -4259744);
time_limit[1] = TextDrawCreate(56.875000, 213.500000, "_");
TextDrawLetterSize(time_limit[1], 0.449999, 1.600000);
TextDrawSetShadow(time_limit[1], 1);
TextDrawFont(time_limit[1], 2);
TextDrawColor(time_limit[1], -1992342160);
http://s45.radikal.ru/i110/1604/9e/394c63bdd449.pnghttp://s017.radikal.ru/i429/1604/79/b29bf3434a0d.pnghttp://s019.radikal.ru/i642/1604/d5/5c10d5ba7cad.png

И оповещение перед киком игрока:

forward DelayedKick(playerid);


_DelayedKick(playerid, time = 500)
{
SetTimerEx("DelayedKick", time, false, "i", playerid);
return 1;
}


public DelayedKick(playerid)
{
Kick(playerid);
return 1;
}

DeimoS
26.04.2016, 15:15
Что за мода пошла поднимать темы 13 года и вместо наглядной конструкции forward,public использовать @.

Я использую "@" как показатель того, что функция вызывается таймером. Это гораздо нагляднее, чем пытаться указывать в имени функции её отношение к таймеру.
Да и некропостинг на форуме не запрещён, как я знаю. Появился у человека вопрос и он его задал в уже существующей теме, а не создал новую. Вполне правильное решение, как по мне

Дуймсос, а Вы мазохист инициализировать переменную при каждом такте таймера.

Больших проблем подобное действо не вызовет. Таймер всего секундный, создаётся только при подключении игрока к серверу и инициализируется всего 3 ячейки. А вот ради какого-то действия, которое будет срабатывать раз в 10 лет, забивать кучу - вот это действительно мазохизм.
На досуге открой мод Аризоны, который слили на днях, и узри, какой код способен держать большой онлайн без каких-либо серьёзных проблем.

Daniel_Cortez
01.05.2016, 21:48
@__login_timer();
@__login_timer()
{
new
i = GetMaxPlayers();

do
{
--i;
if(IsPlayerConnected(i) && player_kick_time{i} != 0 && --player_kick_time{i} == 0)
{
SendClientMessage(i, -1, "Время на регистрацию / авторизацию закончилось, вы кикнуты");
Kick(i);
}
}
while(i);
}

Если GetMaxPlayers вернёт 0, всё будет очень печально.

Пока что перемещу тему обратно в раздел "Добавить мануал".

L0ndl3m
01.05.2016, 22:59
Если GetMaxPlayers вернёт 0, всё будет очень печально.
С чего бы GetMaxPlayers вернёт 0?

Daniel_Cortez
01.05.2016, 23:51
С чего бы GetMaxPlayers вернёт 0?
Перепутал с GetPlayerPoolSize (2 часа ночи, что ещё сказать...)
Впрочем, не помешало бы использовать эту функцию вместо GetMaxPlayers.

L0ndl3m
02.05.2016, 13:10
Впрочем, не помешало бы использовать эту функцию вместо GetMaxPlayers.
Таки-да, в таком случае можно будет предотвратить лишние итерации в цикле.

DeimoS
03.05.2016, 10:22
А ещё можно создать новый итератор в foreach и проверять только тех, кто действительно авторизируется :3 Но это уж совсем для извращенцев.
Я бы всё же остановился на варианте с индивидуальными таймерами или убивал бы таймер, если на данный момент никто не авторизируется. Как-то попусту гонять цикл, как по мне, не комильфо

Daniel_Cortez
03.05.2016, 17:37
А ещё можно создать новый итератор в foreach и проверять только тех, кто действительно авторизируется :3 Но это уж совсем для извращенцев.
Итератор займёт 4004 байта (MAX_PLAYERS + 1 ячеек). Сомнительная польза, особенно на фоне того, что Londlem изначально решил сэкономить с размером массива под время.



Я бы всё же остановился на варианте с индивидуальными таймерами или убивал бы таймер, если на данный момент никто не авторизируется. Как-то попусту гонять цикл, как по мне, не комильфо


static auth_countdown_time[MAX_PLAYERS char];
static auth_countdown_total_players = 0;
static auth_countdown_func_name[] = !"@__AuthCountdownTimer";
static auth_countdown_timer;


StartAuthCountdown(playerid, time)
{
auth_countdown_time{playerid} = time;
if (auth_countdown_total_players++ == 0)
auth_countdown_timer = SetTimer(auth_countdown_func_name, 1000, true);
}

StopAuthCountdown(playerid)
{
auth_countdown_time{playerid} = 0;
if (--auth_countdown_total_players == 0)
KillTimer(auth_countdown_timer);
}

@__AuthCountdownTimer();
@__AuthCountdownTimer()
{
#if defined foreach && !defined FOREACH_NO_PLAYERS
foreach(Player:i)
#else
static i;
for (i = GetPlayerPoolSize() + 1; i-- != 0;) if (IsPlayerConnected(i))
#endif
{
if ((auth_countdown_time{i} != 0) && (--auth_countdown_time{i} == 0))
{
SendClientMessage(i,-1,"Время на регистрацию/авторизацию истекло.");
Kick(i);
}
}
}

И так я случайно изобрёл новый инклуд. Опять.

DeimoS
04.05.2016, 10:28
Итератор займёт 4004 байта (MAX_PLAYERS + 1 ячеек). Сомнительная польза, особенно на фоне того, что Londlem изначально решил сэкономить с размером массива под время.

Ну, во-первых, зависит от того, какое число скрывается за MAX_PLAYERS :D

Во-вторых, если ставить перед собой цель сделать максимально "лёгкий" код, боясь выделить пару лишних байт, то да - такой метод не подойдёт. Но, как по мне, быстродействие и минимальна нагрузка оправдывают подобный жор памяти.
Тем более, что такой итератор можно использовать не только для цикла, но и реализовать другие системы (например, проверку на авторизацию сделать более функциональней, проверяя наличие игрока в итераторе). Зависит от конкретной ситуации

SliM
04.05.2016, 14:19
быстродействие и минимальна нагрузка оправдывают подобный жор памяти.
согласен, лучше потратить дешевую память, в наше то время, чем золотое процессорное время.