Просмотр полной версии : [Мануал] Ограничение времени на регистрацию/авторизацию
Думаю у многих есть такое: Если игрок в течении нескольких секунд не вводит пароль, то его кикает с сервера, и используют таймер для игрока. Сейчас я покажу пример как можно сделать практически то же самое.
В начало скрипта:
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)
Копирование данной статьи без разрешения автора запрещено!
Salvacore
01.11.2013, 16:15
Уже стоит:)
Wilso[N]
02.11.2013, 21:18
Норм, Пригодилось)
ImpreZa177
08.04.2015, 19:35
Eror 017: undefined symbol @__loginTimer ЧТО ДЕЛАТЬ? HELP!!!!
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");
Я бы сделал так:
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");
исправил в общем
Не будет такого. Запуск таймера в коннекте.
Это и являлось причиной ошибки.
Много кто предлагал делать, но: Зачем создавать для каждого игрока таймер? Если можно проверять каждого игрока в цикле, что более надёжнее, нежели проверять определённого.
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");
да этот вариант лучше
Извини никто не скажет как добавить чтобы в чат писалось время это. К примеру:
Оставшее время на авторизацию : 30(--30-29-28-27-26-25-24-23-22-21-20.....)
С убыванием на -1 и как ноль то Кик
Извини никто не скажет как добавить чтобы в чат писалось время это. К примеру:
Оставшее время на авторизацию : 30(--30-29-28-27-26-25-24-23-22-21-20.....)
С убыванием на -1 и как ноль то Кик
выводить в чат каждую секунду время оставшееся на авторизацию - бредовая затея, не думаю что игрокам понравится. Но если все таки хочешь, то создаешь переменную, равную общему времени на авторизацию и в секундном таймере вычитаешь по 1 секунде, обновляешь данные и выводишь игроку в чат.
выводить в чат каждую секунду время оставшееся на авторизацию - бредовая затея, не думаю что игрокам понравится. Но если все таки хочешь, то создаешь переменную, равную общему времени на авторизацию и в секундном таймере вычитаешь по 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;
}
Я не говорю, что этот вариант лучше или оптимизированнее - я не тестировал. Просто ещё один вариант реализации, который мне пришёл на ум
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;
}
Я не говорю, что этот вариант лучше или оптимизированнее - я не тестировал. Просто ещё один вариант реализации, который мне пришёл на ум
Получается к все этому мне надо сделать еще так???
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 на переменную цикла заменить нужно
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);
}
псевдокод
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;
}
У меня код будет выглядить так??
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 использовать @.
Что за мода пошла поднимать темы 13 года и вместо наглядной конструкции forward,public использовать @.
Про @: видимо скриптеры получают от этого какой-то кайф,думая,что открыли неизведанные возможности.
Про @: видимо скриптеры получают от этого какой-то кайф,думая,что открыли неизведанные возможности.
Каждый сам выбирает как будет состоять строение кода его, это же не влияет на работу кода!
По теме:
Я думаю лучше будет использовать тут 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;
}
Что за мода пошла поднимать темы 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, всё будет очень печально.
Пока что перемещу тему обратно в раздел "Добавить мануал".
Если GetMaxPlayers вернёт 0, всё будет очень печально.
С чего бы GetMaxPlayers вернёт 0?
Daniel_Cortez
01.05.2016, 23:51
С чего бы GetMaxPlayers вернёт 0?
Перепутал с GetPlayerPoolSize (2 часа ночи, что ещё сказать...)
Впрочем, не помешало бы использовать эту функцию вместо GetMaxPlayers.
Впрочем, не помешало бы использовать эту функцию вместо GetMaxPlayers.
Таки-да, в таком случае можно будет предотвратить лишние итерации в цикле.
А ещё можно создать новый итератор в 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);
}
}
}
И так я случайно изобрёл новый инклуд. Опять.
Итератор займёт 4004 байта (MAX_PLAYERS + 1 ячеек). Сомнительная польза, особенно на фоне того, что Londlem изначально решил сэкономить с размером массива под время.
Ну, во-первых, зависит от того, какое число скрывается за MAX_PLAYERS :D
Во-вторых, если ставить перед собой цель сделать максимально "лёгкий" код, боясь выделить пару лишних байт, то да - такой метод не подойдёт. Но, как по мне, быстродействие и минимальна нагрузка оправдывают подобный жор памяти.
Тем более, что такой итератор можно использовать не только для цикла, но и реализовать другие системы (например, проверку на авторизацию сделать более функциональней, проверяя наличие игрока в итераторе). Зависит от конкретной ситуации
быстродействие и минимальна нагрузка оправдывают подобный жор памяти.
согласен, лучше потратить дешевую память, в наше то время, чем золотое процессорное время.
Powered by vBulletin® Version 4.2.0 Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot