О switch можно почитать
в статье, написанной Ziggi, о операторах в Pawn.
Если попытаться перевести эту строку кода с машинного языка на человеческий, то смысл этой строки состоит в том, что тут мы указываем оператору switch переменную, значение которой мы будем сравнивать с заданными нами значениями в последующем коде.
Эта строка всё так же относится к switch. Именно тут мы указываем значения, которые будем искать в "dialogid". В данном случае мы указали не число, а член перечисления, который подразумевает под собой ID "1"
if(!response)
{
ShowPlayerDialog(playerid
, dKickMessage
, DIALOG_STYLE_MSGBOX, "Оповещение", "{FFFFFF}Вы были кикнуты с сервера.\n{FF0000}Причина: Отказ от регистрации.\n{FFFFFF}Для выхода с сервера введите \"/q\" в чат", "Вход", "Выход"); }
Тут мы проверяем значение параметра "response". Если оно равно нулю, значит игрок нажал на вторую (правую) кнопку или Esc (то бишь, попытался закрыть диалоговое окно) и поэтому мы его отсоединяем от сервера, показывая диалог-оповещение.
Что за восклицательный знак перед response? Восклицательный знак перед параметром означает то, что мы ожидаем увидеть в "response" значение "false". Следовательно, эта проверка может выглядеть и так "if(response == 0)".
Для тех, кто не в курсе:
false = 0
true = "любое значение, не равное нулю"
if(!strlen(inputtext
)) return ShowPlayerDialog(playerid
, dRegister
, DIALOG_STYLE_INPUT, "Регистрация нового пользователя", "{FF0000}Ошибка: {FFFFFF}Вы не можете продолжить регистрацию не введя пароль!\nВведите пароль для регистрации нового аккаунта:\n{C0C0C0}Примечание:\n{666666}- Пароль чувствителен к регистру.\n- Пароль должен содержать от 4 до 30 символов.\n- Пароль может содержать латинские/кириллические символы и цифры (aA-zZ, аА-яЯ, 0-9).", "Регистрация", "Выход"); else if(strlen(inputtext
) < 4) return ShowPlayerDialog(playerid
, dRegister
, DIALOG_STYLE_INPUT, "Регистрация нового пользователя", "{FF0000}Ошибка: {FFFFFF}Пароль слишком короткий!\nВведите пароль для регистрации нового аккаунта:\n{C0C0C0}Примечание:\n{666666}- Пароль чувствителен к регистру.\n- Пароль должен содержать от 4 до 30 символов.\n- Пароль может содержать латинские/кириллические символы и цифры (aA-zZ, аА-яЯ, 0-9).", "Регистрация", "Выход"); else if(strlen(inputtext
) > 30) return ShowPlayerDialog(playerid
, dRegister
, DIALOG_STYLE_INPUT, "Регистрация нового пользователя", "{FF0000}Ошибка: {FFFFFF}Пароль слишком длинный!\nВведите пароль для регистрации нового аккаунта:\n{C0C0C0}Примечание:\n{666666}- Пароль чувствителен к регистру.\n- Пароль должен содержать от 4 до 30 символов.\n- Пароль может содержать латинские/кириллические символы и цифры (aA-zZ, аА-яЯ, 0-9).", "Регистрация", "Выход"); for(new i
= strlen(inputtext
)-1; i
!= -1; i
--) {
switch(inputtext[i])
{
case '0'..'9', 'а'..'я', 'a'..'z', 'А'..'Я', 'A'..'Z': continue;
default: return ShowPlayerDialog(playerid
, dRegister
, DIALOG_STYLE_INPUT, "Регистрация нового пользователя", "{FF0000}Ошибка: {FFFFFF}Пароль содержит запрещённые символы!\nВведите пароль для регистрации нового аккаунта:\n{C0C0C0}Примечание:\n{666666}- Пароль чувствителен к регистру.\n- Пароль должен содержать от 4 до 30 символов.\n- Пароль может содержать латинские/кириллические символы и цифры (aA-zZ, аА-яЯ, 0-9).", "Регистрация", "Выход"); }
}
Это серия различных проверок того, что ввёл игрок в поле для ввода (в данном случае - это пароль). Вот разбор первых трёх условий
if(!strlen(inputtext
)) // Если игрок ничего не ввёл в поле для ввода... else if(strlen(inputtext
) < 4) // Если длинна введённого игроком текста меньше четырёх символов... else if(strlen(inputtext
) > 30) // Если длинна введённого игроком текста больше 30 символов...
При срабатывании каждого из условий игроку будет показан диалог, в котором будет указано то, какая из проверок не сработала и что игрок сделал не так.
Теперь разберёмся с циклом.
for(new i
= strlen(inputtext
)-1; i
!= -1; i
--) {
switch(inputtext[i])
{
case '0'..'9', 'а'..'я', 'a'..'z', 'А'..'Я', 'A'..'Z': continue;
default: return ShowPlayerDialog(playerid
, dRegister
, DIALOG_STYLE_INPUT, "Регистрация нового пользователя", "{FF0000}Ошибка: {FFFFFF}Пароль содержит запрещённые символы!\nВведите пароль для регистрации нового аккаунта:\n{C0C0C0}Примечание:\n{666666}- Пароль чувствителен к регистру.\n- Пароль должен содержать от 4 до 30 символов.\n- Пароль может содержать латинские/кириллические символы и цифры (aA-zZ, аА-яЯ, 0-9).", "Регистрация", "Выход"); }
}
О циклах можно прочесть, опять же,
в статье, написанной Ziggi об операторах. Я же расскажу подробнее о структуре.
for(new i
= strlen(inputtext
)-1; i
!= -1; i
--) /*--------------------------------------------
new i = strlen(inputtext)-1
// strlen вернёт число символов, введённых игроком в поле для ввода (текст, введённый игроком, хранится в inputtext), но strlen учитывает и нуль-символ, который нам совсем не нужен. Поэтому от возвращённого функцией strlen числа отнимем единицу и запишем это число в переменную "i".
--------------------------------------------
i != -1
// Тут мы задаём условие, которое звучит так: "Если "i" не равно "-1" - совершаем новый такт в цикле. Иначе останавливаем выполнение цикла". Стоит заметить, что проверка "!=" (не равно) подразумевает под собой то, что число "-1" не входит в поле видимости цикла (то есть, при "i" равной "-1", код в теле цикла не сработает. На последней итерации (такте) цикла переменная "i" будет равна "0").
--------------------------------------------
i--
// Ну а тут мы просто отнимаем единицу от значения, хранящегося в "i". Эта запись равносильна следующим:
1) "i -= 1"
2) "i = i - 1"
*/
Ну а это
уже знакомый нам switch, где мы проверяем значение определённой ячейки в массиве (ID этой ячейки хранится в "i")
Немного о кодировках Теперь окунёмся в теоретическую часть, слабо относящуюся к уроку, которая поможет понять код, разбираемый дальше.
Любая машина, которая в перспективе может поднять восстание и уничтожить жизнь на Земле, не понимает ничего, кроме нулей и единиц. Но мы, человеки создавшие этих киборгов-убийц, не согласились плясать под их дудку и придумали различные способы конвертировать привычные нам символы, отличные от нуля и единицы, в привычные киборгам-убийцам нули и единицы. Эти способы мы обозвали кодировками. Кодировок на сегодняшний день есть достаточно много и все они представляют из себя что-то типа таблиц, где за каждым символом, понятным нам, закреплён набор других символов (если кодировка направлена на двоичную систему счисления, с которой и работают машины, то это будет набор нулей и единиц. Ну а если нет, то, в любом случае, данные из отличной от двоичной системы счисления, конвертируются в двоичную систему счисления и только потом подаются машине). И какой бы символ Вы не попытались всунуть машине, она конвертирует его в набор нулей и единиц, опираясь на заданную в неё кодировку, и только потом будет с ним работать (кстати, именно по причине того, что в каждой кодировке за символами может быть закреплено любое кол-во нулей и единиц, которое заблагорассудится создателю этой кодировки, случается искажение текста, если напечатать текст в редакторе с одной кодировкой, а после переключить на другую. То есть, машина не может сама определить кодировку и если в одной кодировке за символом "@" закреплён такой набор нулей и единиц - "01110", а в другой, например, "01010", машина выдаст Вам не "@", а что-то совсем другое).
В общем, наматываем на ус следующее:
1) Однажды Ваш тостер поджарит не хлебушек, а Вас.
2) Машины работают с набором нулей и единиц. Вся информация, какой бы она не была, конвертируется в нули и единицы. А для того, чтоб мы могли как-то контролировать этот процесс, придумали кодировки.
Когда намотка на ус завершена, приступаем к дальнейшему разбору кода.
switch работает исключительно с числами. В case нельзя указать ни переменную, ни слово в привычном для всех виде. Поэтому есть два варианта:
1) Открывать таблицу символов для ASCII кодировки и искать тот набор нулей и единиц, что соответствует нашему символу. Ну и вписывать его.
2) Использовать апостроф и операцию, что я описал в первом пункте, машина сделает за Вас.
В коде выше мы используем именно второй способ, ибо он гораздо нагляднее.
case '0'..'9', 'а'..'я', 'a'..'z', 'А'..'Я', 'A'..'Z': continue;
Как я уже описывал выше, в switch мы проверяем каждый символ в ведённой игроком строке. А тут мы указываем то, какие из символов мы ищем. В данном случае если мы находим одну из цифр или же букв кириллического/латинского алфавита в любом из регистров, то мы пропускаем итерацию и смотрим содержимое следующей ячейки в массиве с строкой. То есть, тут мы указываем все символы, что разрешены в пароле.
default: return ShowPlayerDialog(playerid
, dRegister
, DIALOG_STYLE_INPUT, "Регистрация нового пользователя", "{FF0000}Ошибка: {FFFFFF}Пароль содержит запрещённые символы!\nВведите пароль для регистрации нового аккаунта:\n{C0C0C0}Примечание:\n{666666}- Пароль чувствителен к регистру.\n- Пароль должен содержать от 4 до 30 символов.\n- Пароль может содержать латинские/кириллические символы и цифры (aA-zZ, аА-яЯ, 0-9).", "Регистрация", "Выход");
default в "switch" - это как else в "if". То есть, если ни одно из условий в case не сработало, значит в дело вступает код из default. И в данном случае мы показываем игроку диалог в котором сказано, что тот ввёл запрещённый символ, отличный от перечисленных в case.
Если ни одно из условий выше не сработало, значит игрок удовлетворил все наши правила по поводу введённого пароля и можно приступить к дальнейшей регистрации. Этот код:
pInfo[playerid][pPassword][0] = EOS;
Обнулит значение массива, хранящего пароль, дабы в нём по какой-либо причине не остался пароль предыдущего пользователя при регистрации нового. А этот код:
strins(pInfo
[playerid
][pPassword
], inputtext
, 0);
запишет введённый игроком пароль в массив pInfo, в ячейку с номером, хранящимся в playerid, которая сама разделяется на то число ячеек, сколько членов перечисления указано в enum (в данном случае в ячейку, которая равна ячейке "pPassword", а это ячейка с ID 2).
О функции strins можно прочесть
тут.
А тут
CreateNewAccount(playerid, pInfo[playerid][pPassword]);
Мы вызываем самописанную функцию, в которой будет хранится код создания аккаунта (запросы и прочее).
В диалоге с авторизацией условия практически идентичны, поэтому описывать их не буду, а перейду сразу к новому условию:
Открыть/закрыть Для R39 if(!strcmp(pInfo
[playerid
][pPassword
], inputtext
)) {
new query_string[49+MAX_PLAYER_NAME];
format(query_string
, sizeof(query_string
), "SELECT * FROM `account` WHERE `player_name` = '%s'", pInfo
[playerid
][pName
]); mysql_function_query(mysql_connect_ID, query_string, true, "UploadPlayerAccount","i", playerid);
}
else
{
{
case 0: ShowPlayerDialog(playerid
, dLogin
, DIALOG_STYLE_INPUT, "Авторизация", "{FF0000}Ошибка: {FFFFFF}Вы ввели неверный пароль! У Вас осталось 3 попытки.\nВведите пароль от аккаунта для входа на сервер:", "Вход", "Выход"); case 1: ShowPlayerDialog(playerid
, dLogin
, DIALOG_STYLE_INPUT, "Авторизация", "{FF0000}Ошибка: {FFFFFF}Вы ввели неверный пароль! У Вас осталось 2 попытки.\nВведите пароль от аккаунта для входа на сервер:", "Вход", "Выход"); case 2: ShowPlayerDialog(playerid
, dLogin
, DIALOG_STYLE_INPUT, "Авторизация", "{FF0000}Ошибка: {FFFFFF}Вы ввели неверный пароль! У Вас осталось 1 попытка.\nВведите пароль от аккаунта для входа на сервер:", "Вход", "Выход"); case 3: ShowPlayerDialog(playerid
, dLogin
, DIALOG_STYLE_INPUT, "Авторизация", "{FF0000}Ошибка: {FFFFFF}Вы ввели неверный пароль! У Вас осталась последняя попытка, после чего Вас кикнет.\nВведите пароль от аккаунта для входа на сервер:", "Вход", "Выход"); default:
{
ShowPlayerDialog(playerid
, dKickMessage
, DIALOG_STYLE_MSGBOX, "Оповещение", "{FFFFFF}Вы были кикнуты с сервера.\n{FF0000}Причина: Превышен лимит попыток на ввод пароля.\n{FFFFFF}Для выхода с сервера введите \"/q\" в чат", "Вход", "Выход"); }
}
}
if(!strcmp(pInfo
[playerid
][pPassword
], inputtext
))
Тут мы сравниваем введённый игроком пароль с тем, что загрузили в массив pInfo ранее (при показе диалогов в "FindPlayerInTable")
Если пароли совпали, то отправляем запрос в базу данных, который загрузит из таблицы все данные об игроке и удалим pVar, в котором мы подсчитываем число попыток ввести пароль
new query_string[49+MAX_PLAYER_NAME];
/* Массив, 49 ячеек которого нужны для хранения текста запроса и 24 ячейки (MAX_PLAYER_NAME равно 24)
для хранения ника игрока. Точнее, тут мы указали максимально возможную длину запроса*/
format(query_string
, sizeof(query_string
), "SELECT * FROM `account` WHERE `player_name` = '%s'", pInfo
[playerid
][pName
]); /*SELECT * FROM - Указываем, что нам нужны данные всех столбцов...
`account`- Указываем имя таблицы, в которой нужно искать
WHERE `player_name` = '%s' - Указываем то, на основе каких данных нужно делать выборку (в данном случае грузим все найденные данные, исходя из имени игрока)*/
mysql_function_query(mysql_connect_ID, query_string, true, "UploadPlayerAccount","i", playerid);
/*Напоминаю, что название функции, в которую будут возвращены данные из таблицы, указываются в четвёртом параметре и сейчас эта функция называется "UploadPlayerAccount"*/
Ну а если не совпали, показываем игроку сообщение о том, что он неверно ввёл пароль и прибавляем к pVar для подсчёта попыток единицу. Когда значение pVar будет больше трёх, кикаем игрока.
Для R40 if(!strcmp(pInfo
[playerid
][pPassword
], inputtext
)) {
new query_string[49+MAX_PLAYER_NAME];
format(query_string
, sizeof(query_string
), "SELECT * FROM `account` WHERE `player_name` = '%s'", pInfo
[playerid
][pName
]); mysql_tquery(mysql_connect_ID, query_string, "UploadPlayerAccount","i", playerid);
}
else
{
{
case 0: ShowPlayerDialog(playerid
, dLogin
, DIALOG_STYLE_INPUT, "Авторизация", "{FF0000}Ошибка: {FFFFFF}Вы ввели неверный пароль! У Вас осталось 3 попытки.\nВведите пароль от аккаунта для входа на сервер:", "Вход", "Выход"); case 1: ShowPlayerDialog(playerid
, dLogin
, DIALOG_STYLE_INPUT, "Авторизация", "{FF0000}Ошибка: {FFFFFF}Вы ввели неверный пароль! У Вас осталось 2 попытки.\nВведите пароль от аккаунта для входа на сервер:", "Вход", "Выход"); case 2: ShowPlayerDialog(playerid
, dLogin
, DIALOG_STYLE_INPUT, "Авторизация", "{FF0000}Ошибка: {FFFFFF}Вы ввели неверный пароль! У Вас осталось 1 попытка.\nВведите пароль от аккаунта для входа на сервер:", "Вход", "Выход"); case 3: ShowPlayerDialog(playerid
, dLogin
, DIALOG_STYLE_INPUT, "Авторизация", "{FF0000}Ошибка: {FFFFFF}Вы ввели неверный пароль! У Вас осталась последняя попытка, после чего Вас кикнет.\nВведите пароль от аккаунта для входа на сервер:", "Вход", "Выход"); default:
{
ShowPlayerDialog(playerid
, dKickMessage
, DIALOG_STYLE_MSGBOX, "Оповещение", "{FFFFFF}Вы были кикнуты с сервера.\n{FF0000}Причина: Превышен лимит попыток на ввод пароля.\n{FFFFFF}Для выхода с сервера введите \"/q\" в чат", "Вход", "Выход"); }
}
}
if(!strcmp(pInfo
[playerid
][pPassword
], inputtext
))
Тут мы сравниваем введённый игроком пароль с тем, что загрузили в массив pInfo ранее (при показе диалогов в "FindPlayerInTable")
Если пароли совпали, то отправляем запрос в базу данных, который загрузит из таблицы все данные об игроке и удалим pVar, в котором мы подсчитываем число попыток ввести пароль
new query_string[49+MAX_PLAYER_NAME];
/* Массив, 49 ячеек которого нужны для хранения текста запроса и 24 ячейки (MAX_PLAYER_NAME равно 24)
для хранения ника игрока. Точнее, тут мы указали максимально возможную длину запроса*/
format(query_string
, sizeof(query_string
), "SELECT * FROM `account` WHERE `player_name` = '%s'", pInfo
[playerid
][pName
]); /*SELECT * FROM - Указываем, что нам нужны данные всех столбцов...
`account`- Указываем имя таблицы, в которой нужно искать
WHERE `player_name` = '%s' - Указываем то, на основе каких данных нужно делать выборку (в данном случае грузим все найденные данные, исходя из имени игрока)*/
mysql_tquery(mysql_connect_ID, query_string, "UploadPlayerAccount","i", playerid);
/*Напоминаю, что название функции, в которую будут возвращены данные из таблицы, указываются в четвёртом параметре и сейчас эта функция называется "UploadPlayerAccount"*/
Ну а если не совпали, показываем игроку сообщение о том, что он неверно ввёл пароль и прибавляем к pVar для подсчёта попыток единицу. Когда значение pVar будет больше трёх, кикаем игрока.