shape1
shape2
shape3
shape4
shape7
shape8

Создание системы регистрации msyql R40


laku

Новичок
Пользователь
06.07.2017
1
2
0
Когда я только начинал писать свой первый "недо код" Появилась проблема с mysql и регистрацией(авторизацией).

Эту тему создал специально для новичков, я постараюсь объяснить все понятно если будут вопросы обращайтесь, ну что же начнём, 

1. База данных :

Если у вас есть хост с Phpmyadmin, можете исполосовать его, что бы запустить на локалки есть программа Denwer >>Скачать<<

Установка проста, ну или чекайте в инете ибо я ленивый 

2.Система аккаунтов:

1. Выбераем бд в которой будем создавать таблицу (клик по создать таблицу) и вводим данные о таблице:
В поле "Имя таблицы" вводим "accounts"
В поле "Количество столбцов" вводим "3"

2. Структуру новой таблицы заполняем следующим образом:

Первый столбец

- Имя столбца: id
- Тип столбца: INT
- Длина/значения: 11
Все остальные значения, кроме A_I, не трогаем. Находим A_I (Auto Increment) и ставим галочку.
Идентификаторов не может быть больше одного в таблице. Да оно и не нужно =)

Второй столбец
- Имя столбца: player_name
- Тип столбца: VARCHAR
- Длина/значения: 24 (так как длина ника в SA-MP не может превышать 24 символа)
Все остальные значения не трогаем.

Третий столбец
- Имя столбца: password
- Тип столбца: VARCHAR
- Длина/значения: 30 (Я ограничу длину пароля игрока 30-ю символами. Вы можете сделать меньше/больше)

3.Запускаем pawno:

1. Данные для подключения

В начало нашего скрипта (под "#include ") добавим:

#include <a_mysql>
#define MYSQL_HOST "localhost"//Адрес, по которому расположен MySQL-Сервер
#define MYSQL_USER "root"//Имя пользователя, на которого была создана база данных
#define MYSQL_DATABASE "sa-mp"// Имя базы данных
#define MYSQL_PASSWORD ""//Пароль для доступа к серверу MySQL
new MySQL:mysql_connect_ID;




#include <a_mysq> - подключаем инклюд, в котором хранится объявление всех функций для работы с плагином.
#define MYSQL_HOST "localhost" - Этот макрос хранит в себе адрес хостинга, где хранится база данных (мы будем запускать на ПК, поэтому указываем адрес локальной сети).
#define MYSQL_USER "root" - Этот макрос хранит в себе имя пользователя, у которого имеется доступ к базе данных (так как мы запускаем мод на ПК, у нас это администратор. Когда будете запускать мод на хостинге, Вам выдадут особое имя)
#define MYSQL_DATABASE "first_database" - Этот макрос содержит в себе имя базы данных. Если при создании БД Вы прописывали имя отличное от моего, измените его на то, что указали Вы.
#define MYSQL_PASSWORD "" -- Этот макрос хранит в себе пароль, который требуется для подключения к базе данных
new mysql_connect_ID;
Это целочисленная переменная, в которой мы будем хранить ID подключения, которое потребуется для работы большинства функций.

2. Подключение к базе данных

В OnGameModeInIt

mysql_connect_ID = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE);


Данная функция возвращает ID подключения, который мы и записали в переменную.

3. Ко всем enum

enum e_PLAYER_INFO
{
pID,
pName[MAX_PLAYER_NAME],
pPassword[31]
};
new pInfo[MAX_PLAYERS][e_PLAYER_INFO]; 




enum e_PLAYER_INFO -enum - англ. Enumeration (Перечисление) - это тип, состоящий из набора целочисленных констант
pID, - Первый член перечисления, а по совместительству и ячейка, в которой будет хранится ID аккаунта игрока.
pName[MAX_PLAYER_NAME], - Второй член перечисления, а по совместительству и ячейка, в которой будет хранится имя аккаунта.
pPassword[31] - Третий член массива, а по совместительству и ячейка, в которой будет хранится пароль от аккаунта.
new pInfo[MAX_PLAYERS][e_PLAYER_INFO]; - Массив, через который мы будем обращаться у нужному нам члену перечисления за данными.

4.  Поиск игрока в базе данных и запись ника в массив

GetPlayerName(playerid, pInfo[playerid][pName], MAX_PLAYER_NAME);
new query_string[49+MAX_PLAYER_NAME-4];
format(query_string, sizeof(query_string), "SELECT * FROM `accounts` WHERE `player_name` = '%s'", pInfo[playerid][pName]);
mysql_tquery(mysql_connect_ID, query_string, "FindPlayerInTable","i", playerid);


Так же нам нужно эти данные записать в наш массив.

forward FindPlayerInTable(playerid);
public FindPlayerInTable(playerid)
{
new rows;
cache_get_row_count(rows);
if(!rows)
{
ShowPlayerDialog(playerid, dRegister, DIALOG_STYLE_INPUT, "Регистрация нового пользователя", "Введите пароль для регистрации нового аккаунта:", "Регистрация", "Выход");
}
else
{
ShowPlayerDialog(playerid, dLogin, DIALOG_STYLE_INPUT, "Авторизация", "Введите пароль от аккаунта для того, чтоб продолжить игру:", "Вход", "Выход");
cache_get_value_name(0, "password", pInfo[playerid][pPassword], 31);
}
return 1;
}


5. Создание действий для диалогов

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

Чтоб создать такое перечисление, находим наше перечисление с данными игроков и выше него создадим ещё одно:

enum e_DIALOG_IDs
{
dKickMessage,//Автоматически займёт ID 0
dRegister,//ID 1
dLogin//ID 2
}; 


Всё =) Теперь достаточно придумывать имя каждому новому диалогу, дописывать его в этот список и тогда Вы точно никогда не запутаетесь при создании новых диалогов.

switch(dialogid)
{
case dRegister:
{
if(!response)
{
ShowPlayerDialog(playerid, dKickMessage, DIALOG_STYLE_MSGBOX, "Оповещение", "{FFFFFF}Вы были кикнуты с сервера.\n{FF0000}Причина: Отказ от регистрации.\n{FFFFFF}Для выхода с сервера введите \"/q\" в чат", "Выход", "");
return Kick(playerid);
}
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)
{
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).", "Регистрация", "Выход");
}
}
pInfo[playerid][pPassword][0] = EOS;
strins(pInfo[playerid][pPassword], inputtext, 0);
CreateNewAccount(playerid, pInfo[playerid][pPassword]);
return 1;
}
case dLogin:
{
if(!response)
{
ShowPlayerDialog(playerid, dKickMessage, DIALOG_STYLE_MSGBOX, "Оповещение", "{FFFFFF}Вы были кикнуты с сервера.\n{FF0000}Причина: Отказ от авторизации.\n{FFFFFF}Для выхода с сервера введите \"/q\" в чат", "Выход", "");
return Kick(playerid);
}
if(!strlen(inputtext)) return ShowPlayerDialog(playerid, dLogin, DIALOG_STYLE_INPUT, "Авторизация", "{FF0000}Ошибка: {FFFFFF}Вы не можете продолжить авторизацию не введя пароль!\nВведите пароль от аккаунта для входа на сервер:", "Вход", "Выход");
for(new i = strlen(inputtext)-1; i != -1; i--)
{
switch(inputtext)
{
case '0'..'9', 'а'..'я', 'a'..'z', 'А'..'Я', 'A'..'Z': continue;
default: return ShowPlayerDialog(playerid, dLogin, DIALOG_STYLE_INPUT, "Авторизация", "{FF0000}Ошибка: {FFFFFF}Введённый пароль содержит запрещённые символы!\nВведите пароль от аккаунта для входа на сервер:", "Вход", "Выход");
}
}
if(!strcmp(pInfo[playerid][pPassword], inputtext))
{
new query_string[49+MAX_PLAYER_NAME];
format(query_string, sizeof(query_string), "SELECT * FROM `accounts` WHERE `player_name` = '%s'", pInfo[playerid][pName]);
mysql_tquery(mysql_connect_ID, query_string, "UploadPlayerAccount","i", playerid);
}
else
{
switch(GetPVarInt(playerid, "WrongPassword"))
{
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\" в чат", "Выход", "");
return Kick(playerid);
}
}
SetPVarInt(playerid, "WrongPassword", GetPVarInt(playerid, "WrongPassword")+1);
}
return 1;
}
}


6. Создание/загрузка аккаунта игрока

В самый конец мода вставим этот stock:

stock CreateNewAccount(playerid, password[])
{
new query_string[66+MAX_PLAYER_NAME-4+30];
format(query_string, sizeof(query_string), "INSERT INTO `accounts` (`player_name`, `password`) VALUES ('%s', '%s')", pInfo[playerid][pName], password);
mysql_tquery(mysql_connect_ID, query_string, "UploadPlayerAccountNumber", "i", playerid);


format(query_string, sizeof(query_string), "Аккаунт %s успешно зарегистрирован. Администрация желает Вам приятной игры!", pInfo[playerid][pName]);
SendClientMessage(playerid, 0xFFFFFF00, query_string);
SpawnPlayer(playerid);
return 1;
}  


А вот и сам коллбэк, который вернёт ID аккаунта:

forward UploadPlayerAccountNumber(playerid); 
public UploadPlayerAccountNumber(playerid) pInfo[playerid][pID] = cache_insert_id();


Загрузка аккаунта:

forward UploadPlayerAccount(playerid);
public UploadPlayerAccount(playerid)
{
cache_get_value_name_int(0, "id", pInfo[playerid][pID]);
SendClientMessage(playerid, 0xFFFFFF00, "Вы успешно авторизировались!");
SpawnPlayer(playerid);
return 1;



7.  Сохранение аккаунта

Так же, в самом конце, добавим новый stock

stock SaveAccount(playerid)
{
new query_string[(21)+(16+11)+(20+MAX_PLAYER_NAME)+(16+30)] = "UPDATE `accounts` SET";

format(query_string, sizeof(query_string), "%s `player_name` = '%s',", query_string, pInfo[playerid][pName]);
format(query_string, sizeof(query_string), "%s `password` = '%s'", query_string, pInfo[playerid][pPassword]);

format(query_string, sizeof(query_string), "%s WHERE `id` = '%d'", query_string, pInfo[playerid][pID]);
mysql_tquery(mysql_connect_ID, query_string, "", "");
return 1;



И в OnPlayerDisconnect

SaveAccount(playerid);


8. Отключение от базы данных

Так же нужно не забыть добавить запрос к плагину MySQL на отключение от нашей базы данных. Делается это просто.

В OnGameModeExit 

mysql_close(mysql_connect_ID);


9. Обнуление массива с данными

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

Делается это просто. Сначала в OnPlayerDisconnect, после "SaveAccount(playerid);" добавим:

RemovePlayerInfo(playerid);


А после в конец скрипта:

stock RemovePlayerInfo(playerid)
{
pInfo[playerid][pID] = 0;
pInfo[playerid][pName][0] = EOS;
pInfo[playerid][pPassword][0] = EOS;
return 1;
}


10. Проверка на авторизацию игрока

В начало мода, к переменным, добавим следующий массив:

new player_is_authorized[MAX_PLAYERS char];


Теперь в UploadPlayerAccount/CreateNewAccount, перед SpawnPlayer, добавить

player_is_authorized{playerid} = 1;


В OnPlayerText добавляем следующее:

if(!player_is_authorized{playerid})
{
SendClientMessage(playerid, -1, "Вы не авторизировались и не можете писать в чат!");
return 0;
}  


В начало OnPlayerCommandText

if(!player_is_authorized{playerid}) return SendClientMessage(playerid, -1, "Вы не авторизировались и не можете использовать команды!");  






Автор DeimoS


 
Последнее редактирование модератором:

SeregaMaterazi

Новичок
Пользователь
11.01.2017
0
0
0
А можно скриншот регистрации/авторизации?

 

Daniil_Poltorak

Вжух Вжух Вжух ВЖУХ!
Пользователь
08.07.2015
478
2
11
0
21
@SeregaMaterazi,Зачем скриншот? Можно текст под себя переделать. Ну если руки откуда надо растут.

 

Desais

Новичок
Пользователь
17.05.2017
0
0
0
Что делать если такая ошибка?

C:\Users\nzQ\Desktop\Tournament ñ 0\gamemodes\tdm.pwn(2) : fatal error 100: cannot read from file: "a_
 
Последнее редактирование модератором:

Vitya_Vowkiv

Новичок
Пользователь
16.11.2017
0
0
0
У меня появляеться такая ошибка C:\Users\Þð³é\Desktop\srv-pawno-crmp-c3-win\gamemodes\new.pwn(3) : fatal error 100: cannot read from file: "a_<span class="searchlite""

 
Последнее редактирование модератором:

Almas55541

https://vk.com/almukhametov1
Пользователь
31.07.2017
4
5
0
@Vitya_Vowkiv,  убрать эту строка a_<span class="searchlite" или покажите строку 3

 

Roman345345

Новичок
Пользователь
26.02.2016
34
0
0
Многа ошибок

Код:
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(51) : warning 213: tag mismatch
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(52) : error 017: undefined symbol "playerid"
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(54) : error 017: undefined symbol "playerid"
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(55) : warning 213: tag mismatch
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(55) : error 017: undefined symbol "playerid"
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(62) : warning 213: tag mismatch
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(292) : warning 213: tag mismatch
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(313) : warning 217: loose indentation
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(334) : error 017: undefined symbol "cache_get_value_name"
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(341) : error 017: undefined symbol "cache_get_value_name_int"
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(352) : warning 213: tag mismatch
C:\Documents and Settings\roma\Ðàáî÷èé ñòîë\srv-pawno-crmp-c3-win\gamemodes\new.pwn(368) : warning 213: tag mismatch
Pawn compiler 3.2.3664	 	 	Copyright (c) 1997-2006, ITB CompuPhase


5 Errors.