PDA

Просмотр полной версии : [Вопрос] Время бана



ORLADOK
18.08.2018, 22:38
Такой вопрос возник: рационально ли сохранять текущее значение GetTickCount() и дату (в разные переменные) в БД, а затем его извлекать по дате и обновленному GetTickCount()?

То бишь, идея такова:
Игрок игрался со спичками, в последствие чего был выдана его блокировка. Игрок заходит на сервер и тут БД выискивает `ban_status` (есть или нет = 1/0), затем, если он действительно забанен, выписывает из БД две переменные, скажем, `ban_ticks` (int) и `ban_date` (sql date, аля string для pawn). После выписки программа получает дату сегодняшнего дня. Если конвертация последней строки не больше 0, записанной в `ban_date`, то идет оповещение о блокировке. А иначе идет выписывание из `ban_ticks` в ее переименную, после чего следует подсчет в +/-, что значит [разблокировка, если `ban_ticks` > GetTickCount()] или оповещение о прежней блокировке соответственно.

Надеюсь не слишком мутно отписал. Пока сижу на форуме, могу переобозначить.

Да, муть навел... Идея в том, что GetTickCount() будет обнуляться при рестарте, а его я планировал делать ежедневно. А посему такие тики, вероятно, должны быть идентичны (e.g. 16:40:57:XX ~ 16:40:57:YY)?

Elrmrnt-Kritik
18.08.2018, 22:55
А почему бы не использовать в базе данных у столбца ban_date формат TIMESTAMP (0000-00-00 00:00:00)?
Соответственно, чтобы этот столбец принимал значение времени бана, нужно при выдаче самого бана сделать так:

UPDATE players_bans SET ban_date = NOW() WHERE id = (ид аккаунта)

Где NOW() - текущее время. Аналогично создаем еще один столбец unban_date (я бы назвал их date_ban и date_unban). В него записываем время бана плюс срок бана. Соответственно, время нынешнее - NOW(), а для прибавления к дате используем математическую операцию сложения совместно с DAY, MONTH, YEAR, SEC. Например,

UPDATE players_bans SET unban_date = NOW() + INTERVAL 5 DAY + INTERVAL 2 HOUR


Так, дата разбана наступит через пять дней и два часа. Также можно проверить SQL запросом, забанен ли игрок (если да, получить данные о бане и заблокировать доступ к серверу):


SELECT * FROM players_bans WHERE unban_date > NOW() AND id = (ид аккаунта)


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

И да, а зачем Вам статус бана? Вы создайте отдельную таблицу с забаненными игроками. Для добавления туда забаненного используйте INSERT INTO, а при разбане используйте DELETE FROM.

ORLADOK
18.08.2018, 23:21
Действительно, проверку SQL инъекциями я что-то продинамил. Ранее я использовал NOW() и мне он сильно приглянулся, однако, до такого (вашего) метода у меня голова не дошла. Перегрелся, что сказать.

Спасибо.

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

Статус бана мне нужен для OnPlayerRequestClass.

Как идет подключение к серверу:

Ищу игрока в базе аккаунтов по имени;
- Если игрок не найден, то идет диалог о регистрации на сервере;
- Если игрок найден, то получаю статус бана [она есть]. Согласен, после этого шага можно залезать уже в таблицу с блокировками.
- Если игрок найден и блокировки нет, то идет авторизация.

Elrmrnt-Kritik
19.08.2018, 02:53
А почему бы не сделать что-то вроде такого?

new Cache:gAccountCache[MAX_PLAYERS];


public OnPlayerConnect(playerid)
{
SetTimerEx("@CheckAccountData", 2*1000, false, "i", playerid);
return 1;
}


@CheckAccountData(playerid);
@CheckAccountData(playerid)
{
static const string_query[] = "SELECT p.*, b.*, (b.unban - NOW()) AS diff FROM players AS p LEFT JOIN players_bans AS b ON p.id = b.id WHERE p.name = '%s' LIMIT 1";

new string[sizeof string_query+(-2+MAX_PLAYER_NAME)+1];
GetPlayerName(playerid, string, MAX_PLAYER_NAME);

format(string, sizeof string, string_query, string);
new Cache:result = mysql_query(dbHandle, string);

if(cache_num_rows()) // the account is exists
{
gAccountCache[playerid] = cache_save();

new diff;
cache_get_value_name_int(0, "diff", diff);

if(diff > 0){
OnPlayerBanned(playerid); // player banned
}
else{
OnPlayerAuthorization(playerid); // player registred
}
}
else{
OnPlayerRegistration(playerid);

cache_delete(result);
}


return 1;
}


stock OnPlayerBanned(playerid)
{
cache_set_active(gAccountCache[playerid]);

new adminname[MAX_PLAYER_NAME], string[MAX_CHATBUBBLE_LENGTH];
cache_get_value_name(0, "admin_name", adminname, MAX_PLAYER_NAME);

format(string, sizeof string, "Вы забанены администратором %s", adminname);
SendClientMessage(playerid, -1, string);

SetTimerEx("Kick", 250, false, "i", playerid);
return 1;
}


stock OnPlayerAuthorization(playerid)
{
cache_set_active(gAccountCache[playerid]);

/* загрузка всех данных аккаунта этого игрока */
return 1;
}


stock OnPlayerRegistration(playerid)
{
/* регистрация */
return 1;
}


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

Забыл добавить удаление аккаунта из банлиста. Вот более правильный вариант.

new Cache:gAccountCache[MAX_PLAYERS];
new gAccountID[MAX_PLAYERS]; // не стал писать enum, но его использовать логичнее


public OnPlayerConnect(playerid)
{
SetTimerEx("@CheckAccountData", 2*1000, false, "i", playerid);
return 1;
}


@CheckAccountData(playerid);
@CheckAccountData(playerid)
{
static const string_query[] = "SELECT p.*, b.*, (b.unban - NOW()) AS diff FROM players AS p LEFT JOIN players_bans AS b ON p.id = b.id WHERE p.name = '%s' LIMIT 1";

new string[sizeof string_query+(-2+MAX_PLAYER_NAME)+1];
GetPlayerName(playerid, string, MAX_PLAYER_NAME);

format(string, sizeof string, string_query, string);
new Cache:result = mysql_query(dbHandle, string);

if(cache_num_rows()) // the account is exists
{
gAccountCache[playerid] = cache_save();

new diff;
cache_get_value_name_int(0, "diff", diff);

if(diff > 0){
OnPlayerBanned(playerid); // player banned
}
else if(diff == 0){
PLAYER_AUTHORIZATION:
OnPlayerAuthorization(playerid); // player registred
}
else{

cache_get_value_name_int(0, "id", gAccountID[playerid]);
format(string, sizeof string, "DELETE FROM players_bans WHERE id = %d LIMIT 1", gAccountID[playerid]);
mysql_tquery(dbHandle, string);

goto PLAYER_AUTHORIZATION;
}
}
else{
OnPlayerRegistration(playerid);

cache_delete(result);
}


return 1;
}


stock OnPlayerBanned(playerid)
{
cache_set_active(gAccountCache[playerid]);

new adminname[MAX_PLAYER_NAME], string[MAX_CHATBUBBLE_LENGTH];
cache_get_value_name(0, "admin_name", adminname, MAX_PLAYER_NAME);

format(string, sizeof string, "Вы забанены администратором %s", adminname);
SendClientMessage(playerid, -1, string);

SetTimerEx("Kick", 250, false, "i", playerid);
return 1;
}


stock OnPlayerAuthorization(playerid)
{
cache_set_active(gAccountCache[playerid]);

/* загрузка всех данных аккаунта этого игрока */
return 1;
}


stock OnPlayerRegistration(playerid)
{
/* регистрация */
return 1;
}