PDA

Просмотр полной версии : [Мануал] Система блокировки аккаунта по дням с авторазбаном [MySQL R39-6]



Skull
28.08.2016, 18:08
Здравствуйте, уважаемые пользователи форума Pro-Pawn.
Сегодня я решил написать для Вас систему блокировки аккаунта по дням с авторазбаном на MySQL R39-6.
В интернете я нашел пару таких систем, но они очень старой реализации и, к тому же, на данном форуме такой темы я не обнаружил.
Мы будем использовать MySQL R39-6, DC_CMD (можете использовать и другой, кроме стандартного, к примеру ZCMD, Pawn.CMD и так далее), sscanf 2.8.2, а также понадобится фикс для функции Kick (можете использовать фикс от Daniel_Cortez (http://pro-pawn.ru/member.php?100-Daniel_Cortez) или другой).

Важно: Плюс ко всему нужен будет фикс кодировки MySQL от $continue$ (http://pro-pawn.ru/showthread.php?13641-%D0%A0%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D1%8B-%D1%81-%D0%BA%D0%BE%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%BE%D0%B9-%D0%B2-MySQL-R33), чтобы в базу данных верно записывались буквы русского алфавита.

Необходимые файлы:
MySQL R39-6 (https://github.com/pBlueG/SA-MP-MySQL/releases)
DC_CMD v2.8 (http://rgho.st/53289178)
dc_kickfix (https://www.dropbox.com/s/f6s558qn2xkhom6/dc_kickfix.inc?dl=0)
sscanf v2.8.2 (https://github.com/maddinat0r/sscanf/releases)
banlist.sql (http://rgho.st/8nMQyNwNz)

Собственно, приступим.

В OnPlayerConnect, в самое начало:

static const auto_query_string[] =
"SELECT * FROM `banlist` WHERE `Name` = '%s'";
new
playerid_name[MAX_PLAYER_NAME + 1],
query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];

GetPlayerName(playerid, playerid_name, MAX_PLAYER_NAME);
format(query_string, sizeof(query_string), auto_query_string, playerid_name);
mysql_function_query(1, query_string, true, "OnPlayerFindInBanlist", "d", playerid);

Ко всем public добавляем следующие два:

forward OnPlayerUnban(playerid, targetid_name[]);
public OnPlayerUnban(playerid, targetid_name[])
{
new
rows,
fields;

cache_get_data(rows, fields);

if(!rows)
return SendClientMessage(playerid, -1, !"Аккаунт не найден.");

static const auto_query_string[] =
"DELETE FROM `banlist` WHERE `Name` = '%s'";
new
query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];

format(query_string, sizeof(query_string), auto_query_string, targetid_name);
mysql_function_query(1, query_string, false, "", "");

format(query_string, sizeof(query_string), "Аккаунт %s разбанен.", targetid_name);
SendClientMessage(playerid, -1, query_string);
return 1;
}


forward OnPlayerFindInBanlist(playerid);
public OnPlayerFindInBanlist(playerid)
{
new
rows,
fields,
unbanunixtime;

cache_get_data(rows, fields);

if(rows)
{
unbanunixtime = cache_get_field_content_int(0, !"UnbanUNIXTime", 1);

new
playerid_name[MAX_PLAYER_NAME + 1],
admin_name[MAX_PLAYER_NAME + 1];

GetPlayerName(playerid, playerid_name, MAX_PLAYER_NAME);

if(gettime() >= unbanunixtime)
{
static const auto_query_string[] =
"DELETE FROM `banlist` WHERE `Name` = '%s'";
new
query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];

format(query_string, sizeof(query_string), auto_query_string, playerid_name);
mysql_function_query(1, query_string, false, "", "");
return 1;
}

static const auto_string[] =
"Ваш аккаунт заблокирован Администратором {ff6347}%s. {ffffff}Причина: {ff6347}%s.";
new
string[sizeof(auto_string) - 2 + MAX_PLAYER_NAME - 2 + 32 + 1],
days_string[4+1],
word_string[8+1],
reason[32+1],
days = (unbanunixtime - gettime()) / 86400 + 1;

cache_get_field_content(0, !"Admin", admin_name);
cache_get_field_content(0, !"Reason", reason);

GetDeclensionWord(word_string, sizeof(word_string), days, "Остался", "Осталось", "Осталось");
GetDeclensionWord(days_string, sizeof(days_string), days, "день", "дня", "дней");

format(string, sizeof(string), auto_string, admin_name, reason);
SendClientMessage(playerid, -1, string);

format(string, sizeof(string), "%s {ff6347}%d %s {ffffff}до разблокировки.", word_string, days, days_string);
SendClientMessage(playerid, -1, string);

Kick(playerid);
}
return 1;
}

Ко всем stock:

stock GetDeclensionWord(result[], const size = sizeof(result), num, word_1[], word_2[], word_3[])
{
num %= 100;

if (num > 19) {
num %= 10;
}

result[0] = '\0';
switch (num) {
case 1: {
strcat(result, word_1, size);
}
case 2..4: {
strcat(result, word_2, size);
}
default: {
strcat(result, word_3, size);
}
}
}

И последний шаг - добавляем две команды бана и разбана игрока (либо в конец мода, либо там, где все Ваши команды):

CMD:ban(playerid, params[])
{
// if(!IsPlayerAdmin(playerid)) return 1;

new
targetid,
days,
days_string[4+1],
targetid_name[MAX_PLAYER_NAME+1],
playerid_name[MAX_PLAYER_NAME+1];

if(sscanf(params, !"uds[120]", targetid, days, params[0]))
return SendClientMessage(playerid, -1, !"Использование: /ban [ID/Ник] [Кол-во дней] [Причина]");
if(targetid == INVALID_PLAYER_ID)
return SendClientMessage(playerid, -1, !"Игрок не найден.");
if(!(1 <= days <= 100))
return SendClientMessage(playerid, -1, !"Неверное количество дней. Доступно: 1-100.");
if(strlen(params[0]) > 32)
return SendClientMessage(playerid, -1, !"Длина причины должна быть не больше 32х символов.");

GetPlayerName(playerid, playerid_name, MAX_PLAYER_NAME);
GetPlayerName(targetid, targetid_name, MAX_PLAYER_NAME);

GetDeclensionWord(days_string, sizeof(days_string), days, "день", "дня", "дней");

static const auto_string[] =
"Администратор %s[%d] забанил(а) %s[%d] на %d %s. Причина: %s";
new
string[sizeof(auto_string) - 2 + MAX_PLAYER_NAME - 2 + 4 - 2 + MAX_PLAYER_NAME - 2 + 4 - 2 + 3 - 2 + 4 - 2 + 32 + 1],
unbanunixtime = gettime() + days * 86400;

format(string, sizeof(string), auto_string, playerid_name, playerid, targetid_name, targetid, days, days_string, params[0]);
SendClientMessageToAll(-1, string);

static const auto_query_string[] =
"INSERT INTO `banlist` (`Name`, `Reason`, `Admin`, `BanDate`, `UnbanUNIXTime`) "\
"VALUES ('%s', '%s', '%s', '%s', '%d')";
new
query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME - 2 + 32 - 2 + MAX_PLAYER_NAME - 2 + 20 - 2 + 11 + 1],
date_string[20+1],
year,
month,
day,
hour,
minute,
second;

getdate(year, month, day);
gettime(hour, minute, second);
format(date_string, sizeof(date_string), "%02d.%02d.%d, %02d:%02d:%02d", day, month, year, hour, minute, second);

format(query_string, sizeof(query_string), auto_query_string, targetid_name, params[0], playerid_name, date_string, unbanunixtime);
mysql_function_query(1, query_string, false, "", "");

TogglePlayerControllable(targetid, 0);
Kick(targetid);
return 1;
}


CMD:unban(playerid, params[])
{
// if(!IsPlayerAdmin(playerid)) return 1;

if(isnull(params))
return SendClientMessage(playerid, -1, !"Использование: /unban [Ник]");

if(strlen(params) > MAX_PLAYER_NAME)
return SendClientMessage(playerid, -1, !"Длина ника не должна превышать 24х символов.");

static auto_query_string[] =
"SELECT * FROM `banlist` WHERE `Name` = '%e'";
new
query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];

mysql_format(1, query_string, sizeof(query_string), auto_query_string, params);
mysql_function_query(1, query_string, true, !"OnPlayerUnban", "ds", playerid, params);
return 1;
}

Скриншоты:

http://s012.radikal.ru/i319/1608/f7/a7286a851dbf.png
http://s010.radikal.ru/i313/1608/6e/1af6884a539a.png
http://s020.radikal.ru/i715/1608/b1/d3ef37316cff.png
http://s020.radikal.ru/i701/1608/a8/4f217b7ec32c.png

Примечание:
Проверку на администратора выставьте свою, ибо у каждого она разная, для примера я показал как сделать эти команды только для RCON администратора.


Если есть какие-нибудь ошибки/недочеты или же пожелания и дополнения, то с радостью Вас выслушаю. :)


При копировании урока на другие порталы, просьба указывать автора.

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

Profyan
28.08.2016, 19:05
Почему ты упаковываешь строки в SendClientMessage, но остальные строки ты не упаковываешь? Либо упаковывай все, либо ничего, хотя для упакованных тебе придется format на strcet поменять еще.

Son of the Moon
28.08.2016, 19:08
хватит уже блоки делать по одному же и тому принципу, сделайте плагин на сериал или еще что-то, и уже будет что-то новое.

Skull
28.08.2016, 19:24
Почему ты упаковываешь строки в SendClientMessage, но остальные строки ты не упаковываешь? Либо упаковывай все, либо ничего, хотя для упакованных тебе придется format на strcet поменять еще.

format не поддерживает запакованные строки.

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


хватит уже блоки делать по одному же и тому принципу, сделайте плагин на сериал или еще что-то, и уже будет что-то новое.

Сказал тот, кто выложил древнейшую систему логирования на данный форум. Не суть. Это простейшая система, которая должна быть у каждого на сервере.

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



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

Вот поэтому.

Desulaid
28.08.2016, 20:27
+1 лишнее, sizeof возвращает как раз таки эту единицу.

Son of the Moon
28.08.2016, 22:23
Сказал тот, кто выложил древнейшую систему логирования на данный форум. Не суть. Это простейшая система, которая должна быть у каждого на сервере.

У тебя новизна зашкаливает. на MySQL перевел и все, цены прям нет, на твою систему.

Igor_Stalker
28.08.2016, 22:29
Сделай на ORM

Fallen A.
28.08.2016, 23:41
Сделай на ORM

ORM априори говно. Хочешь им обмазаться? Дерзай.

Паблики
OnPlayerFindInBanlist, OnPlayerUnban вообще не нужны.

Объясню почему: в данном случае тебя не нужна "псевдомногопоточность" и с ней, в данном случае, скорее всего, ты больше проиграешь, чем выиграешь. Можно все оформить в одну функцию и несколько раз обращаться к ней, нежели нагромождать код.

Igor_Stalker
28.08.2016, 23:43
и чем же ORM говно?

Fallen A.
29.08.2016, 00:00
и чем же ORM говно?

Ты тратишь больше времени и памяти на отправку запроса. Взять хотя бы то, что ORM, это тот же макрос или функция, не более.

И да, олдфаги мускула любят ручками составлять запросы, а не одной функцией. ИМХО.

ziggi
29.08.2016, 01:36
ORM априори говно. Хочешь им обмазаться? Дерзай.

Ты тратишь больше времени и памяти на отправку запроса. Взять хотя бы то, что ORM, это тот же макрос или функция, не более.

И да, олдфаги мускула любят ручками составлять запросы, а не одной функцией. ИМХО.


Чушь. Удобство, предоставляемое возможностями ORM не сравнится с незначительными потерями производительности. Но потери производительности при использовании ORM быть не может, ибо самые ресурсозатратные операции (конструирование запроса) выполняются на быстром C++, а не в медленном (относительно C++) Pawn с помощью format и strcat. Более того, тебе никто не запрещает использовать SQL одновременно используя ORM.

Так что выражения вида "ORM априори говно" лучше оставить для разговоров в подъезде, а здесь принято "отвечать за базар".


Паблики
OnPlayerFindInBanlist, OnPlayerUnban вообще не нужны.

Объясню почему: в данном случае тебя не нужна "псевдомногопоточность" и с ней, в данном случае, скорее всего, ты больше проиграешь, чем выиграешь. Можно все оформить в одну функцию и несколько раз обращаться к ней, нежели нагромождать код.

Это совсем не "псевдо", а нормальная многопоточность. Зачем заставлять зависать весь сервер на время ожидания результата запроса? Пусть это и будет практически незаметно, но зачем?

В каком месте ты увидел нагромождение? Всю систему можно поместить в один inlude файл, тогда всё будет опрятно и удобно.

А автора можно отругать за хранение времени в виде строки и за бардак, устроенный из-за склонений.


stock GetDeclensionWord(result[], const size = sizeof(result), num, word_1[], word_2[], word_3[])
{
num %= 100;

if (num > 19) {
num %= 10;
}

result[0] = '\0';
switch (num) {
case 1: {
strcat(result, word_1, size);
}
case 2..4: {
strcat(result, word_2, size);
}
default: {
strcat(result, word_3, size);
}
}
}

Использовать так:


GetDeclensionWord(day_string, sizeof(day_string), days, "день", "дня", "дней");

$continue$
29.08.2016, 03:23
Пропущен 3 аргумент в функции. (в примере)



stock GetDeclensionWord(result[], const size = sizeof(result), num, word_1[], word_2[], word_3[])



GetDeclensionWord(day_string, sizeof(day_string), "день", "дня", "дней");

Fallen A.
29.08.2016, 03:30
Чушь. Удобство, предоставляемое возможностями ORM не сравнится с незначительными потерями производительности. Но потери производительности при использовании ORM быть не может, ибо самые ресурсозатратные операции (конструирование запроса) выполняются на быстром C++, а не в медленном (относительно C++) Pawn с помощью format и strcat. Более того, тебе никто не запрещает использовать SQL одновременно используя ORM.

Так что выражения вида "ORM априори говно" лучше оставить для разговоров в подъезде, а здесь принято "отвечать за базар".



Это совсем не "псевдо", а нормальная многопоточность. Зачем заставлять зависать весь сервер на время ожидания результата запроса? Пусть это и будет практически незаметно, но зачем?

В каком месте ты увидел нагромождение? Всю систему можно поместить в один inlude файл, тогда всё будет опрятно и удобно.

А автора можно отругать за хранение времени в виде строки и за бардак, устроенный из-за склонений.


stock GetDeclensionWord(result[], const size = sizeof(result), num, word_1[], word_2[], word_3[])
{
num %= 100;

if (num > 19) {
num %= 10;
}

result[0] = '\0';
switch (num) {
case 1: {
strcat(result, word_1, size);
}
case 2..4: {
strcat(result, word_2, size);
}
default: {
strcat(result, word_3, size);
}
}
}

Использовать так:


GetDeclensionWord(day_string, sizeof(day_string), "день", "дня", "дней");




stock get_Word(total, form1[32], form2[32], form3[32])
{
#define abs(%1) %1<0?~%1+1:%1
total = abs(total) % 1000;
if(1 < total < 5 ) return form2;
if( total == 1) return form1;
return form3;
#undef abs
}




Что касается нагромождения, то я бы не стал использовать кучу public для минимального набора действий.

Для меня ORM как было говном априори, так им и осталось.

123
29.08.2016, 06:04
CMD:unban(playerid, params[])
{
// if(!IsPlayerAdmin(playerid)) return 1;

if(isnull(params)) // зачем тратить процессорное время, когда строка уже передана через params?
return SendClientMessage(playerid, -1, !"Использование: /unban [Ник]");

if(strlen(params) > 24) // без этой проверки, твой автоматический подсчет строк рухнет;(
return SendClientMessage(playerid, -1, !"Длина ника не должна превышать 24-символов.");

static const auto_query_string[] =
"SELECT * FROM `banlist` WHERE `Name` = '%e'";
new
query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];

mysql_format(1, query_string, sizeof(query_string), auto_query_string, params); // SQL-инъекция?
mysql_function_query(1, query_string, true, !"OnPlayerUnban", "ds", playerid, params);
return 1;
}

И много всего в таком духе. Да и подобный подсчет строк в стиле Daniel_Cortez, здесь совсем неуместен. Система бана, как уже выражался автор, очень проста и содержится в каждом моде, и она одна из таких функций - которую сделал и забыл. И жертвовать временем компиляции ради непонятного "удобства" - мне не понятно. И код бы смотрелся гораздо меньше и приятней.

ziggi
29.08.2016, 09:15
Что касается нагромождения, то я бы не стал использовать кучу public для минимального набора действий.

Не кучу, а два. Ты бы не стал, а я стал. Кто прав? Никто, поэтому навязывать свои убеждения того "как надо" не стоит.


Для меня ORM как было говном априори, так им и осталось.

Какой смысл об этом писать без каких-либо убедительных доводов? Не можешь чем-то подкрепить слова - лучше их и не писать.




if(strlen(params) > 24) // без этой проверки, твой автоматический подсчет строк рухнет;(
return SendClientMessage(playerid, -1, !"Длина ника не должна превышать 24-символов.");


О чём ты? Ничего не рухнет.



mysql_format(1, query_string, sizeof(query_string), auto_query_string, params); // SQL-инъекция?}

Где? mysql_format защищает от этого.



И много всего в таком духе. Да и подобный подсчет строк в стиле Daniel_Cortez, здесь совсем неуместен. Система бана, как уже выражался автор, очень проста и содержится в каждом моде, и она одна из таких функций - которую сделал и забыл. И жертвовать временем компиляции ради непонятного "удобства" - мне не понятно. И код бы смотрелся гораздо меньше и приятней.

Дак и подсчёт очень прост, сделал и забыл. И кому есть дело до времени компиляции? Тем более, что разница будет не более миллисекунды.

123
29.08.2016, 09:53
Не кучу, а два. Ты бы не стал, а я стал. Кто прав? Никто, поэтому навязывать свои убеждения того "как надо" не стоит.



Какой смысл об этом писать без каких-либо убедительных доводов? Не можешь чем-то подкрепить слова - лучше их и не писать.



О чём ты? Ничего не рухнет.



Где? mysql_format защищает от этого.



Дак и подсчёт очень прост, сделал и забыл. И кому есть дело до времени компиляции? Тем более, что разница будет не более миллисекунды.

Посмотри оригинальный вариант и мой, я уже все исправил, а так отметил причину. А по поводу проверки на длину - как раз таки рухнет, поскольку в оригинальном варианте -


if(sscanf(params, !"s[120]", params[0]))

Выделяется 120 ячеек, а подсчет идет c MAX_PLAYER_NAME + 1 (25 ячеек).

ziggi
29.08.2016, 10:01
А по поводу проверки на длину - как раз таки рухнет, поскольку в оригинальном варианте -


if(sscanf(params, !"s[120]", params[0]))

Выделяется 120 ячеек, а подсчет идет c MAX_PLAYER_NAME + 1 (25 ячеек).

Согласен, не заметил.

P.S. Лучше воспользоваться MAX_PLAYER_NAME, вместо числа в чистом виде.

123
29.08.2016, 10:18
P.S. Лучше воспользоваться MAX_PLAYER_NAME, вместо числа в чистом виде.

Согласен, но даже 24 ячейки смысла нет использовать. Если длина ника больше 20, человека в игру не пустит. Поэтому во всех модах (где есть система регистрации), ограничение в 20 символов при смене ника, а выкидывать 4 ячейки в воздух, не в духе микрооптимизаторов этого форума))

ziggi
29.08.2016, 11:01
Согласен, но даже 24 ячейки смысла нет использовать. Если длина ника больше 20, человека в игру не пустит. Поэтому во всех модах (где есть система регистрации), ограничение в 20 символов при смене ника, а выкидывать 4 ячейки в воздух, не в духе микрооптимизаторов этого форума))

Лучше перестраховаться и использовать максимальный размер.

Skull
29.08.2016, 14:44
Чушь. Удобство, предоставляемое возможностями ORM не сравнится с незначительными потерями производительности. Но потери производительности при использовании ORM быть не может, ибо самые ресурсозатратные операции (конструирование запроса) выполняются на быстром C++, а не в медленном (относительно C++) Pawn с помощью format и strcat. Более того, тебе никто не запрещает использовать SQL одновременно используя ORM.

Так что выражения вида "ORM априори говно" лучше оставить для разговоров в подъезде, а здесь принято "отвечать за базар".



Это совсем не "псевдо", а нормальная многопоточность. Зачем заставлять зависать весь сервер на время ожидания результата запроса? Пусть это и будет практически незаметно, но зачем?

В каком месте ты увидел нагромождение? Всю систему можно поместить в один inlude файл, тогда всё будет опрятно и удобно.

А автора можно отругать за хранение времени в виде строки и за бардак, устроенный из-за склонений.


stock GetDeclensionWord(result[], const size = sizeof(result), num, word_1[], word_2[], word_3[])
{
num %= 100;

if (num > 19) {
num %= 10;
}

result[0] = '\0';
switch (num) {
case 1: {
strcat(result, word_1, size);
}
case 2..4: {
strcat(result, word_2, size);
}
default: {
strcat(result, word_3, size);
}
}
}

Использовать так:


GetDeclensionWord(day_string, sizeof(day_string), days, "день", "дня", "дней");


Спасибо. Не знал, что так можно реализовать. Исправил.

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



CMD:unban(playerid, params[])
{
// if(!IsPlayerAdmin(playerid)) return 1;

if(isnull(params)) // зачем тратить процессорное время, когда строка уже передана через params?
return SendClientMessage(playerid, -1, !"Использование: /unban [Ник]");

if(strlen(params) > 24) // без этой проверки, твой автоматический подсчет строк рухнет;(
return SendClientMessage(playerid, -1, !"Длина ника не должна превышать 24-символов.");

static const auto_query_string[] =
"SELECT * FROM `banlist` WHERE `Name` = '%e'";
new
query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];

mysql_format(1, query_string, sizeof(query_string), auto_query_string, params); // SQL-инъекция?
mysql_function_query(1, query_string, true, !"OnPlayerUnban", "ds", playerid, params);
return 1;
}

И много всего в таком духе. Да и подобный подсчет строк в стиле Daniel_Cortez, здесь совсем неуместен. Система бана, как уже выражался автор, очень проста и содержится в каждом моде, и она одна из таких функций - которую сделал и забыл. И жертвовать временем компиляции ради непонятного "удобства" - мне не понятно. И код бы смотрелся гораздо меньше и приятней.

И Вам спасибо. Не учёл о возможности инъекции (кстати, почему-то ругается на 4 аргумент (auto_query_string), пришлось использовать без автоподсчёта) и совсем забыл, что можно использовать isnull.

Sp1ke
29.08.2016, 14:47
Спасибо. Не знал, что так можно реализовать. Исправил.

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



И Вам спасибо. Не учёл о возможности инъекции (кстати, почему-то ругается на 4 аргумент (auto_query_string), пришлось использовать без автоподсчёта) и совсем забыл, что можно использовать isnull.

Используй обычный static вместо static const. Зачем каждый раз вызывать GetPlayerName? Создай переменную и запиши туда ник игрока, и на всякий случай сделай для этого макрос, так как у многих таковое уже имеется

Skyline
29.08.2016, 22:23
error 017: undefined symbol "GetDeclensionWord"
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition

На каждой этой функции столько ошибок.

GetDeclensionWord(days_string, sizeof(days_string), days, "день", "дня", "дней");

Freaky
29.08.2016, 23:18
error 017: undefined symbol "GetDeclensionWord"
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition

На каждой этой функции столько ошибок.

GetDeclensionWord(days_string, sizeof(days_string), days, "день", "дня", "дней");

вот:

Чушь. Удобство, предоставляемое возможностями ORM не сравнится с незначительными потерями производительности. Но потери производительности при использовании ORM быть не может, ибо самые ресурсозатратные операции (конструирование запроса) выполняются на быстром C++, а не в медленном (относительно C++) Pawn с помощью format и strcat. Более того, тебе никто не запрещает использовать SQL одновременно используя ORM.

Так что выражения вида "ORM априори говно" лучше оставить для разговоров в подъезде, а здесь принято "отвечать за базар".



Это совсем не "псевдо", а нормальная многопоточность. Зачем заставлять зависать весь сервер на время ожидания результата запроса? Пусть это и будет практически незаметно, но зачем?

В каком месте ты увидел нагромождение? Всю систему можно поместить в один inlude файл, тогда всё будет опрятно и удобно.

А автора можно отругать за хранение времени в виде строки и за бардак, устроенный из-за склонений.


stock GetDeclensionWord(result[], const size = sizeof(result), num, word_1[], word_2[], word_3[])
{
num %= 100;

if (num > 19) {
num %= 10;
}

result[0] = '\0';
switch (num) {
case 1: {
strcat(result, word_1, size);
}
case 2..4: {
strcat(result, word_2, size);
}
default: {
strcat(result, word_3, size);
}
}
}

Использовать так:


GetDeclensionWord(day_string, sizeof(day_string), days, "день", "дня", "дней");

Skyline
29.08.2016, 23:22
Спасибо, такой вопрос еще, а как сделать, чтобы если аккаунт заблокирован, то авторизация не появлялась?
Тут вроде нет проверки на бан игрока. Вот public загрузки. Подскажите пожалуйста.


public UploadPlayerAccount(playerid)
{
PlayerInfo[playerid][pID] = cache_get_field_content_int(0, "ID", mysql_connect_id);
PlayerInfo[playerid][pSex] = cache_get_field_content_int(0, "pol", mysql_connect_id);
PlayerInfo[playerid][pSkin] = cache_get_field_content_int(0, "skin", mysql_connect_id);
PlayerInfo[playerid][pSpawn] = cache_get_field_content_int(0, "spawn", mysql_connect_id);
PlayerInfo[playerid][pHealth] = cache_get_field_content_int(0, "health", mysql_connect_id);
PlayerInfo[playerid][pMoney] = cache_get_field_content_int(0, "money", mysql_connect_id);
PlayerInfo[playerid][pBank] = cache_get_field_content_int(0, "bank", mysql_connect_id);
PlayerInfo[playerid][pAdmin] = cache_get_field_content_int(0, "admin", mysql_connect_id);
PlayerInfo[playerid][pLevel] = cache_get_field_content_int(0, "level", mysql_connect_id);
PlayerInfo[playerid][pExp] = cache_get_field_content_int(0, "exp", mysql_connect_id);
PlayerInfo[playerid][pMuted] = cache_get_field_content_int(0, "mute", mysql_connect_id);
PlayerInfo[playerid][pMutedTime] = cache_get_field_content_int(0, "mutetime", mysql_connect_id);
PlayerInfo[playerid][pLeader] = cache_get_field_content_int(0, "leader", mysql_connect_id);
PlayerInfo[playerid][pMember] = cache_get_field_content_int(0, "fraction", mysql_connect_id);
PlayerInfo[playerid][pRank] = cache_get_field_content_int(0, "rank", mysql_connect_id);
PlayerInfo[playerid][pModel] = cache_get_field_content_int(0, "fmodel", mysql_connect_id);
PlayerInfo[playerid][pCarLic] = cache_get_field_content_int(0, "prava", mysql_connect_id);
PlayerInfo[playerid][pFlyLic] = cache_get_field_content_int(0, "vozduhlic", mysql_connect_id);
PlayerInfo[playerid][pVip] = cache_get_field_content_int(0, "vip", mysql_connect_id);
PlayerInfo[playerid][pHourGame] = cache_get_field_content_int(0, "hourgame", mysql_connect_id);
PlayerInfo[playerid][pWarns] = cache_get_field_content_int(0, "warn", mysql_connect_id);
PlayerInfo[playerid][pBlocks] = cache_get_field_content_int(0, "block", mysql_connect_id);
PlayerInfo[playerid][pInvited] = cache_get_field_content_int(0, "data_invite", mysql_connect_id);
PlayerInfo[playerid][pRanged] = cache_get_field_content_int(0, "data_rank", mysql_connect_id);
PlayerInfo[playerid][pPayDay] = cache_get_field_content_int(0, "payday", mysql_connect_id);
PlayerInfo[playerid][pUpgrade] = cache_get_field_content_int(0, "upgrade", mysql_connect_id);
SendClientMessage(playerid, COLOR_WHITE,!"Добро пожаловать на сервер - {FFDEAD}AscarY.");
if(PlayerInfo[playerid][pAdmin] > 0)
{
new arank[64];
switch(PlayerInfo[playerid][pAdmin])
{
case 6: arank = "Гл.Администратор";
case 5: arank = "Гл.Модератор";
case 1..4: arank = "Модератор";
}
new string[100];
format(string, sizeof(string), "Ты зашёл как {FFDEAD}%s",arank);
SendClientMessage(playerid, COLOR_WHITE,string);
}
if(PlayerInfo[playerid][pVip] == 1) SendClientMessage(playerid, COLOR_WHITE,!"У тебя {FFDEAD}VIP Аккаунт 1 Уровня.");
if(PlayerInfo[playerid][pVip] == 2) SendClientMessage(playerid, COLOR_WHITE,!"У тебя {FFDEAD}VIP Аккаунт 2 Уровня.");
SetPlayerScore(playerid, PlayerInfo[playerid][pLevel]);
GivePlayerMoney(playerid,PlayerInfo[playerid][pMoney]);
PlayerLogged{playerid} = true;
SetPlayerSpawn(playerid);
SpawnPlayer(playerid);
return 1;
}

DeimoS
29.08.2016, 23:36
В OnPlayerConnect, где идёт проверка на наличие аккаунта, делай проверку перед диалогом авторизации.
Переписать систему авторизации придётся немного, если всё по уму сделать хочешь.

Должно быть так:

public OnPlayerConnect(...)
{
if(игрок зарегистрирован?)
{//Нет
Регистрация
}
else
{//Да
Запрос в таблицу "banlist" (ищешь игрока в списке забаненных
}
return 1;
}



коллбэк_вызываемый_запросом
{
if(забанен)
{
Игрок забанен => кик
}
else
{
Авторизация
}
return 1;
}

Skyline
29.08.2016, 23:54
Получилось, но на половину.
Проблема появилась такая, аккаунт не забанен, но пароль не подходит, т.е. ввожу пароль, а в игру не входит.

Вот как вышло.


public FindPlayerInTable(playerid)
{
new rows, fields, string[300];
cache_get_data(rows, fields);
if(!rows)
{
SendClientMessage(playerid, COLOR_WHITE, "Этот ник не {FF0000}зарегистрирован {FFFFFF}на этом сервере! Зарегистрируйся, пожалуйста.");
format(string,sizeof(string),"{FFDEAD}Здравствуй, %s \n\n- Ты зашел на сервер AscarY(0.3.7)[RUS/UA]\n- Игровой Режим: AscarY: LS/SF/LV\n- На сервере: \n- Бизнесов: \n- Сбизнесов: \n- Сайт Сервера: \n\nИспользуемый тобой ник свободен.\nЗарегистрируйся чтобы продолжить.\n\nЗадай пароль от аккаунта:",PlayerInfo[playerid][pName]);
ShowPlayerDialog(playerid, 1 ,DIALOG_STYLE_INPUT,!"Регистрация",string,"Далее","Отмена");
}
else
{
static const auto_query_string[] = "SELECT * FROM `banlist` WHERE `Name` = '%s'";
new query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];
format(query_string, sizeof(query_string), auto_query_string, PlayerInfo[playerid][pName]);
mysql_function_query(mysql_connect_id, query_string, true, "OnPlayerFindInBanlist", "d", playerid);
}
return 1;
}




public OnPlayerFindInBanlist(playerid)
{
new rows, fields, unbanunixtime, string[250+ MAX_PLAYER_NAME + 1];
cache_get_data(rows, fields);
if(rows)
{
unbanunixtime = cache_get_field_content_int(0, !"UnbanUNIXTime", 1);
new playerid_name[MAX_PLAYER_NAME + 1], admin_name[MAX_PLAYER_NAME + 1];
GetPlayerName(playerid, playerid_name, MAX_PLAYER_NAME);
if(gettime() >= unbanunixtime)
{
static const auto_query_string[] = "DELETE FROM `banlist` WHERE `Name` = '%s'";
new query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];
format(query_string, sizeof(query_string), auto_query_string, playerid_name);
mysql_function_query(mysql_connect_id, query_string, false, "", "");
return 1;
}
new days_string[4+1],
word_string[8+1],
reason[32+1],
days = (unbanunixtime - gettime()) / 86400 + 1;
cache_get_field_content(0, !"Admin", admin_name);
cache_get_field_content(0, !"Reason", reason);
GetDeclensionWord(word_string, sizeof(word_string), days, "Остался", "Осталось", "Осталось");
GetDeclensionWord(days_string, sizeof(days_string), days, "день", "дня", "дней");
format(string,sizeof(string),"Аккаунт {FF6347}%s{ffffff} временно {FF6347}заблокирован.{ffffff}",playerid_name);
SendClientMessage(playerid, -1, string);
format(string,sizeof(string),"Причина: {FF6347}%s{ffffff}. Забанил: {FF6347}%s.",reason, admin_name);
SendClientMessage(playerid, -1, string);
format(string, sizeof(string), "%s: {ff6347}%d %s {ffffff}до {FF6347}разблокировки.", word_string, days, days_string);
SendClientMessage(playerid, -1, string);
Kick(playerid);
}
else
{
format(string,sizeof(string),"{FFDEAD}Здравствуй, %s \n\n- Ты зашел на сервер AscarY (0.3.7)[RUS/UA]\n- Игровой режим: AscarY: LS/SF/LV(RPG)\n- На сервере:\n- Бизнесов: \n- Сбизнесов: \n- Сайт Сервера: \n\nЭтот аккаунт уже зарегистрирован\n\nВведи пароль от аккаунта:",PlayerInfo[playerid][pName]);
ShowPlayerDialog(playerid,2,DIALOG_STYLE_PASSWORD,!"Авторизация",string,"Вход","Отмена");
cache_get_field_content(0, "password", PlayerInfo[playerid][pPassword], mysql_connect_id, 25);
}
return 1;
}

123
30.08.2016, 05:44
Получилось, но на половину.
Проблема появилась такая, аккаунт не забанен, но пароль не подходит, т.е. ввожу пароль, а в игру не входит.

Вот как вышло.


public FindPlayerInTable(playerid)
{
new rows, fields, string[300];
cache_get_data(rows, fields);
if(!rows)
{
SendClientMessage(playerid, COLOR_WHITE, "Этот ник не {FF0000}зарегистрирован {FFFFFF}на этом сервере! Зарегистрируйся, пожалуйста.");
format(string,sizeof(string),"{FFDEAD}Здравствуй, %s \n\n- Ты зашел на сервер AscarY(0.3.7)[RUS/UA]\n- Игровой Режим: AscarY: LS/SF/LV\n- На сервере: \n- Бизнесов: \n- Сбизнесов: \n- Сайт Сервера: \n\nИспользуемый тобой ник свободен.\nЗарегистрируйся чтобы продолжить.\n\nЗадай пароль от аккаунта:",PlayerInfo[playerid][pName]);
ShowPlayerDialog(playerid, 1 ,DIALOG_STYLE_INPUT,!"Регистрация",string,"Далее","Отмена");
}
else
{
static const auto_query_string[] = "SELECT * FROM `banlist` WHERE `Name` = '%s'";
new query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];
format(query_string, sizeof(query_string), auto_query_string, PlayerInfo[playerid][pName]);
mysql_function_query(mysql_connect_id, query_string, true, "OnPlayerFindInBanlist", "d", playerid);
}
return 1;
}




public OnPlayerFindInBanlist(playerid)
{
new rows, fields, unbanunixtime, string[250+ MAX_PLAYER_NAME + 1];
cache_get_data(rows, fields);
if(rows)
{
unbanunixtime = cache_get_field_content_int(0, !"UnbanUNIXTime", 1);
new playerid_name[MAX_PLAYER_NAME + 1], admin_name[MAX_PLAYER_NAME + 1];
GetPlayerName(playerid, playerid_name, MAX_PLAYER_NAME);
if(gettime() >= unbanunixtime)
{
static const auto_query_string[] = "DELETE FROM `banlist` WHERE `Name` = '%s'";
new query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];
format(query_string, sizeof(query_string), auto_query_string, playerid_name);
mysql_function_query(mysql_connect_id, query_string, false, "", "");
return 1;
}
new days_string[4+1],
word_string[8+1],
reason[32+1],
days = (unbanunixtime - gettime()) / 86400 + 1;
cache_get_field_content(0, !"Admin", admin_name);
cache_get_field_content(0, !"Reason", reason);
GetDeclensionWord(word_string, sizeof(word_string), days, "Остался", "Осталось", "Осталось");
GetDeclensionWord(days_string, sizeof(days_string), days, "день", "дня", "дней");
format(string,sizeof(string),"Аккаунт {FF6347}%s{ffffff} временно {FF6347}заблокирован.{ffffff}",playerid_name);
SendClientMessage(playerid, -1, string);
format(string,sizeof(string),"Причина: {FF6347}%s{ffffff}. Забанил: {FF6347}%s.",reason, admin_name);
SendClientMessage(playerid, -1, string);
format(string, sizeof(string), "%s: {ff6347}%d %s {ffffff}до {FF6347}разблокировки.", word_string, days, days_string);
SendClientMessage(playerid, -1, string);
Kick(playerid);
}
else
{
format(string,sizeof(string),"{FFDEAD}Здравствуй, %s \n\n- Ты зашел на сервер AscarY (0.3.7)[RUS/UA]\n- Игровой режим: AscarY: LS/SF/LV(RPG)\n- На сервере:\n- Бизнесов: \n- Сбизнесов: \n- Сайт Сервера: \n\nЭтот аккаунт уже зарегистрирован\n\nВведи пароль от аккаунта:",PlayerInfo[playerid][pName]);
ShowPlayerDialog(playerid,2,DIALOG_STYLE_PASSWORD,!"Авторизация",string,"Вход","Отмена");
cache_get_field_content(0, "password", PlayerInfo[playerid][pPassword], mysql_connect_id, 25);
}
return 1;
}


Как ты получаешь значение пароля из таблицы с банами? Я конечно все понимаю, но думать хоть чуть-чуть нужно. Получай значение пароля в FindPlayerInTable (там ведь запрос в таблицу аккаунтов?) или дублируй запрос в таблицу аккаунтов из OnPlayerConnect (желательно конечно первое, что бы не дублировать одинаковые запросы).

Вообщем, если выше я написал слишком сложно, то скопируй это с заменой -


public FindPlayerInTable(playerid)
{
new rows, fields, string[300];
cache_get_data(rows, fields);
if(!rows)
{
SendClientMessage(playerid, COLOR_WHITE, "Этот ник не {FF0000}зарегистрирован {FFFFFF}на этом сервере! Зарегистрируйся, пожалуйста.");
format(string,sizeof(string),"{FFDEAD}Здравствуй, %s \n\n- Ты зашел на сервер AscarY(0.3.7)[RUS/UA]\n- Игровой Режим: AscarY: LS/SF/LV\n- На сервере: \n- Бизнесов: \n- Сбизнесов: \n- Сайт Сервера: \n\nИспользуемый тобой ник свободен.\nЗарегистрируйся чтобы продолжить.\n\nЗадай пароль от аккаунта:",PlayerInfo[playerid][pName]);
ShowPlayerDialog(playerid, 1 ,DIALOG_STYLE_INPUT,!"Регистрация",string,"Далее","Отмена");
}
else
{
cache_get_field_content(0, "password", PlayerInfo[playerid][pPassword], mysql_connect_id, 25);

static const auto_query_string[] = "SELECT * FROM `banlist` WHERE `Name` = '%s'";
new query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];

format(query_string, sizeof(query_string), auto_query_string, PlayerInfo[playerid][pName]);
mysql_function_query(mysql_connect_id, query_string, true, "OnPlayerFindInBanlist", "d", playerid);
}
return 1;
}


public OnPlayerFindInBanlist(playerid)
{
new rows, fields, unbanunixtime, string[250+ MAX_PLAYER_NAME + 1];
cache_get_data(rows, fields);
if(rows)
{
unbanunixtime = cache_get_field_content_int(0, !"UnbanUNIXTime", 1);
new playerid_name[MAX_PLAYER_NAME + 1], admin_name[MAX_PLAYER_NAME + 1];
GetPlayerName(playerid, playerid_name, MAX_PLAYER_NAME);
if(gettime() >= unbanunixtime)
{
static const auto_query_string[] = "DELETE FROM `banlist` WHERE `Name` = '%s'";
new query_string[sizeof(auto_query_string) - 2 + MAX_PLAYER_NAME + 1];
format(query_string, sizeof(query_string), auto_query_string, playerid_name);
mysql_function_query(mysql_connect_id, query_string, false, "", "");
return 1;
}
new days_string[4+1],
word_string[8+1],
reason[32+1],
days = (unbanunixtime - gettime()) / 86400 + 1;
cache_get_field_content(0, !"Admin", admin_name);
cache_get_field_content(0, !"Reason", reason);
GetDeclensionWord(word_string, sizeof(word_string), days, "Остался", "Осталось", "Осталось");
GetDeclensionWord(days_string, sizeof(days_string), days, "день", "дня", "дней");
format(string,sizeof(string),"Аккаунт {FF6347}%s{ffffff} временно {FF6347}заблокирован.{ffffff}",playerid_name);
SendClientMessage(playerid, -1, string);
format(string,sizeof(string),"Причина: {FF6347}%s{ffffff}. Забанил: {FF6347}%s.",reason, admin_name);
SendClientMessage(playerid, -1, string);
format(string, sizeof(string), "%s: {ff6347}%d %s {ffffff}до {FF6347}разблокировки.", word_string, days, days_string);
SendClientMessage(playerid, -1, string);
Kick(playerid);
}
else
{
format(string,sizeof(string),"{FFDEAD}Здравствуй, %s \n\n- Ты зашел на сервер AscarY (0.3.7)[RUS/UA]\n- Игровой режим: AscarY: LS/SF/LV(RPG)\n- На сервере:\n- Бизнесов: \n- Сбизнесов: \n- Сайт Сервера: \n\nЭтот аккаунт уже зарегистрирован\n\nВведи пароль от аккаунта:",PlayerInfo[playerid][pName]);
ShowPlayerDialog(playerid,2,DIALOG_STYLE_PASSWORD,!"Авторизация",string,"Вход","Отмена");
}
return 1;
}

Skyline
30.08.2016, 12:55
Спасибо большое.

Skull
30.08.2016, 14:03
error 017: undefined symbol "GetDeclensionWord"
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition
warning 202: number of arguments does not match definition

На каждой этой функции столько ошибок.

GetDeclensionWord(days_string, sizeof(days_string), days, "день", "дня", "дней");

Извиняюсь, забыл добавить stock. Исправил.

fujitake
11.08.2019, 15:16
Скиньте таблицу у кого есть

DeimoS
11.08.2019, 15:47
Так по INSERT-запросу же легко восстановить таблицу вручную.

Как-то так:

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

CREATE TABLE `banlist` (
`id` int(11) NOT NULL,
`Name` varchar(24) NOT NULL,
`Admin` varchar(24) NOT NULL,
`Reason` varchar(33) NOT NULL,
`BanDate` varchar(21) NOT NULL,
`UnbanUNIXTime` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


ALTER TABLE `banlist`
ADD PRIMARY KEY (`id`);


ALTER TABLE `banlist`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

Хотя не советовал бы использовать данную систему. Всё можно сделать гораздо проще и лучше.