Доступ к готовым решениям

Переход в группу "Пользователь"

300.00
Одноразовый платёж
Быстрый переход в группу "Пользователи", без надобности написания постов и ожидания.

Покупка дает возможность:
Быть полноправным участником форума
Нормальное копирование кода
Создавать темы
Скачивать файлы
Доступ к архиву Pawno-Info

Урок Оригинальная система регистрации на MYSQL R39-7

Snape

Начинающий
Пользователь
Регистрация
3 Июн 2013
Сообщения
99
Лучшие ответы
0
Репутация
13
Представляю вашему вниманию оригинальную систему регистрации.
Подобного вида система используется на RP-Gameworld. Уверен, данная система внесет каплю разнообразия на ваш сервер.

Видео
- демонстрация системы

Описание
Каждый пункт динамичен и выполнен в виде переключателя. С помощью этой системы вы сможете собрать в одном месте все поля для ввода данных, которые вам необходимо получить от игрока (к примеру, email, код безопасности, раса и т.д., и т.п.)
Скрипт тестировался на чистом проекте, который я приложу в конце темы и создавался с ориентиром на использование его в модах типа "с нуля". Но приложив совсем чуть-чуть усилий, его можно с легкостью адаптировать под любой мод.
К некоторым строкам в коде добавлено описание для пущего понимания.

Урок

Для начала нам необходимо создать базу данных. Для этого откройте панель управления базой и с помощью запросов импортируйте таблицу:

Сама база:
Код:
CREATE DATABASE `newmod` DEFAULT CHARACTER SET cp1251 COLLATE cp1251_general_ci;
USE `newmod`;
И непосредственно таблица
Код:
CREATE TABLE IF NOT EXISTS `accounts` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Nickname` varchar(32) NOT NULL,
  `Password` varchar(64) NOT NULL,
  `Level` int(11) NOT NULL DEFAULT '1',
  `Sex` int(11) NOT NULL,
  `Referal` varchar(64) NOT NULL DEFAULT 'No',
  `Admin` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB  DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1;
Скриншот пустой таблицы

Подключаем mysql плагин. Как указано в шапке темы, для этой системы я использовал mysql от blueg версии R39-7
PHP:
#include <a_mysql>
Добавляем необходимые идентификаторы
PHP:
#define REG_DIALOG 555
#define LOG_DIALOG 777
#define TABLE_ACCOUNTS "accounts" //название таблицы с аккаунтами
#define SQL_HOST "localhost" //хост базы
#define SQL_USER "root" //имя пользователя
#define SQL_DB "newmod" //имя базы, к которой мы подключаемся
#define SQL_PASS "" //пароль
#define SQL_PORT 3306 //порт соединения
#define SQL_RECONNECT true //переподключение в случае ошибок
#define SQL_POOLSIZE 10 //максимальное к-лво одновременных подключений (необходимо для mysql_pquery)
#define MIN_PASS_LENGTH 6 //минимальная длинна пароля
#define MAX_PASS_LENGTH 64  //максимальная длинна пароля
#define ENCRYPT_PASS 1 //Значение 1 включает шифрование пароля в диалоге. Т.е. при пароле 123123 будет, к примеру ***123
Добавляем необходимые переменные и конструкции
PHP:
/* Данные */
enum regdata
{
	pAcceptRules,
	pSex,
	pReferal[32+1],
	pPassword[64]
}
new RegData[MAX_PLAYERS][regdata]; //хранение информации при регистрации

enum player_data
{
	pDatabaseID,
	pName[MAX_PLAYER_NAME+1],
	pPassword[64],
	pReferal[32+1],
	pLevel,
	pSex,
	pAdmin,
	bool:pLogged
}
new pData[MAX_PLAYERS][player_data]; //хранение информации авторизованого игрока
new WrongPass[MAX_PLAYERS];
new TextStr[512]; //массив для форматирования самого диалога регистрации

/* MYSQL */
new MySQL; //для записи connection handle (номер соединения)
Добавляем форварды
PHP:
/* Форварды */
forward IsValidAccount(playerid);
forward OnPlayerRegister(playerid);
forward LoadPlayerAccount(playerid);
Далее в любое свободное место объявляем коллбеки к этим форвардам
PHP:
public LoadPlayerAccount(playerid)
{
	if(cache_get_row_count(MySQL) == 1)
	{
		/* Грузим данные из БД на сервер */
		pData[playerid][pDatabaseID] = cache_get_field_content_int(0, "ID", MySQL);
		cache_get_field_content(0, "Referal", pData[playerid][pReferal], MySQL, 64);
		pData[playerid][pLevel] = cache_get_field_content_int(0, "Level", MySQL);
		pData[playerid][pSex] = cache_get_field_content_int(0, "Sex", MySQL);
		pData[playerid][pAdmin] = cache_get_field_content_int(0, "Admin", MySQL);

		pData[playerid][pLogged] = true; //авторизуем
		SendClientMessage(playerid, -12, "Данные успешно загружены. Приятной игры!");
		SpawnPlayer(playerid);

		/* Тестовые функции для првоерки загрузки */
		print("\n\n==============================================  ===");
		printf("Nickname: %s", pData[playerid][pName]);
		printf("DB: %i", pData[playerid][pDatabaseID]);
		printf("Referal: %s", pData[playerid][pReferal]);
		printf("Level: %d", pData[playerid][pLevel]);
		printf("Sex: %d", pData[playerid][pSex]);
		printf("Admin: %d", pData[playerid][pAdmin]);
		print("=================================================\  n\n");
	}
	return 1;
}

public IsValidAccount(playerid)
{
	if(cache_get_row_count(MySQL) == 1) //если нашло 1 нужный нам аккаунт
	{
		cache_get_row(0, 2, pData[playerid][pPassword], MySQL, 64); //заправшиваем пароль для проверки

		SendClientMessage(playerid, -1, "Ваш аккаунт успешно найден в базе данных. Пройдите пожалуйста авторизацию");
		ShowPlayerDialog(playerid, LOG_DIALOG, DIALOG_STYLE_INPUT, "Авторизация", "Ваш аккаунт найден в базе данных\nПожалуйста, авторизуйтесь..", ">>", "Выход");
	}
	else //если 1 нужный нам аккаунт не найден
	{
		SendClientMessage(playerid, -1, "Ваш аккаунт не найден в базе данных. Пройдите пожалуйста регистрацию");
		ResetRegData(playerid); //обнуляем данные
		ShowRegisterDialog(playerid);
	}
	return 1;
}
public OnPlayerRegister(playerid)
{
	pData[playerid][pDatabaseID] = cache_insert_id(); //записываем ид аккаунта в базе. По нему мы будем сохранять аккаунт. В БД он добавляется автоматически
	pData[playerid][pLevel] = 1;
	pData[playerid][pAdmin] = 0;

	pData[playerid][pLogged] = true; //авторизуем

	SpawnPlayer(playerid);
	SendClientMessage(playerid, -1, "Поздравляем с успешной регистрацией!!!");
	return 1;
}
Добавляем несколько необходимых стоков
PHP:
stock ResetRegData(playerid)
{
	RegData[playerid][pAcceptRules] = 0;
	RegData[playerid][pSex] = 0;
	RegData[playerid][pReferal] = EOS;
	RegData[playerid][pPassword] = EOS;
	return 1;
}
stock RemovePlayerData(playerid)
{
	pData[playerid][pLevel] = 1;
	pData[playerid][pSex] = 0;
	pData[playerid][pAdmin] = 0;
	pData[playerid][pLogged] = false; 
	WrongPass[playerid] = 0;
	return 1;
}

stock UpdatePlayerData(playerid)
{
	if(!pData[playerid][pLogged]) return 1; //не сохраняем, если игрок не авторизован

	new save_query[512]; //замените этот массив на свой массив, который вы используете для запросов, если он есть
	new str_q[128];

	format(str_q, sizeof str_q, "UPDATE `"TABLE_ACCOUNTS"` SET "), strcat(save_query, str_q);

	format(str_q, sizeof str_q, "`Nickname` = '%s',", pData[playerid][pName]), strcat(save_query, str_q);
	format(str_q, sizeof str_q, "`Password` = '%s',", pData[playerid][pPassword]), strcat(save_query, str_q);
	format(str_q, sizeof str_q, "`Level` = '%d',", pData[playerid][pLevel]), strcat(save_query, str_q);
	format(str_q, sizeof str_q, "`Sex` = '%d',", pData[playerid][pSex]), strcat(save_query, str_q);
	format(str_q, sizeof str_q, "`Referal` = '%s',", pData[playerid][pReferal]), strcat(save_query, str_q);
	format(str_q, sizeof str_q, "`Admin` = '%d'", pData[playerid][pAdmin]), strcat(save_query, str_q);

	format(str_q, sizeof str_q," WHERE `ID` = '%i'", pData[playerid][pDatabaseID]), strcat(save_query, str_q);
	mysql_tquery(MySQL, save_query, "", "");
	return 1;
}
stock ShowRegisterDialog(playerid)
{
	new str_local[64], switch_str[32];
	TextStr = "\0"; //предварительно очищаем

	switch(RegData[playerid][pAcceptRules]) //тут мы просто проверяем, сколько страниц правил просмотрел игрок
	{
		case 0,1: switch_str = "Не ознакомлены";
		default: switch_str = "Ознакомлены";
	}
	format(str_local, sizeof(str_local), "Правила сервера\t{86a366}%s\n", switch_str), strcat(TextStr, str_local);

	switch(RegData[playerid][pSex]) //тут мы просто проверяем, сколько страниц правил просмотрел игрок
	{
		case 1: switch_str = "Мужской";
		case 2: switch_str = "Женский";
		default: switch_str = "Не указан";
	}
	format(str_local, sizeof(str_local), "Пол персонажа\t{86a366}%s\n", switch_str), strcat(TextStr, str_local);

	/*
		Что до пункта реферал, то тут уж можете доделывать, либо заменить на какой угодно параметр
		Я же для наглядности просто буду проверять длинну никнейма
	*/
	if(strlen(RegData[playerid][pReferal]) < 4)
	{
		format(str_local, sizeof(str_local), "Реферал\t{86a366}Не указан\n"), strcat(TextStr, str_local);
	}
	else format(str_local, sizeof(str_local), "Реферал\t{86a366}%s\n", RegData[playerid][pReferal]), strcat(TextStr, str_local);

	if(strlen(RegData[playerid][pPassword]) < MIN_PASS_LENGTH || strlen(RegData[playerid][pPassword]) > MAX_PASS_LENGTH)
	{
		format(str_local, sizeof(str_local), "Пароль\t{86a366}Не указан\n"), strcat(TextStr, str_local);
	}
	else //если пароля подходит по длинне
	{
		#if ENCRYPT_PASS

		new encrypt_pass[64];
		strcat(encrypt_pass, RegData[playerid][pPassword], 64); //лублируем текст, чтобы над ним можно было совершать манипуляции
		strdel(encrypt_pass, 0, strlen(encrypt_pass)-3); //удаляем все символы, кроме 3 последних
		for(new s; s < strlen(RegData[playerid][pPassword])-3; s++) strins(encrypt_pass, "*", 0); //вставляем звездочки в начало текста

		format(str_local, sizeof(str_local), "Пароль\t{86a366}%s\n", encrypt_pass), strcat(TextStr, str_local); //тут необходимо показать измененную строчку

		#else

		/*
			Тут мы не используем шифрование, поэтому вставляем RegData[playerid][pPassword]
		*/
		format(str_local, sizeof(str_local), "Пароль\t{86a366}%s\n", RegData[playerid][pPassword]), strcat(TextStr, str_local);

		#endif
	}
	format(str_local, sizeof(str_local), "Завершить регистрацию >>"), strcat(TextStr, str_local);

	ShowPlayerDialog(playerid, REG_DIALOG, DIALOG_STYLE_TABLIST, "Регистрация", TextStr, ">>",  "");
	return 1;
}
Поясню за всё, что мы добавили:

LoadPlayerAccount(playerid) - загружает данные игрока после успешной авторизации
IsValidAccount(playerid) - проверяет, существует ли в базе данных аккаунт
OnPlayerRegister(playerid) - вызывается после самой регистрации и добавления аккаунта в базу данных
ResetRegData(playerid) - обнуляет переменные, которые мы использовали для заполнения полей при регистрации
RemovePlayerData(playerid) - обнуляет переменные, используемые для хранения данных игрока (необходимо использовать как минимум при коннекте или дисконнекте)
UpdatePlayerData(playerid) - сохраняет данные авторизованного игрока

В паблик OnGameModeInit добавляем код, который соединит сервер с нашей базой данных
PHP:
    MySQL = mysql_connect(SQL_HOST, SQL_USER, SQL_DB, SQL_PASS, SQL_PORT, SQL_RECONNECT, SQL_POOLSIZE);
    mysql_log(LOG_ALL, LOG_TYPE_HTML);
    if(mysql_errno() != 0) print("[-] MYSQL Connection does not exist");
    else
	{
		print("[+] MYSQL Connection accepted ");
		mysql_query(MySQL, "SET NAMES 'cp1251'",false);
		mysql_set_charset("cp1251", MySQL);
	}
В OnGameModeExit добавляем отключение от БД
PHP:
mysql_close(); //закрываем соединение
В начало пабликов OnPlayerRequestClass и OnPlayerRequestSpawn добавляем код, который не позволит неавторизованному игроку перейти к спавну
PHP:
if(!pData[playerid][pLogged]) return 0;
В OnPlayerConnect добавляем следующий код
PHP:
	new db_str[128]; //создаем массив для формирования запроса
	RemovePlayerData(playerid); //очищаем данные энуменатора player_data

	GetPlayerName(playerid, pData[playerid][pName], MAX_PLAYER_NAME); //запрашиваем имя

	/* форматируем и отправляем запрос */
	mysql_format(MySQL, db_str, sizeof(db_str), "SELECT * FROM `"TABLE_ACCOUNTS"` WHERE `Nickname` = '%e'", pData[playerid][pName]);
	mysql_pquery(MySQL, db_str, "IsValidAccount", "d", playerid);

	SetSpawnInfo(playerid, 0, 222, 1128.9762,-1488.1531,22.7690,360.0000, 0, 0, 0, 0, 0, 0); //устанавливаем данные для спавна (необходимо для теста)
В паблике OnDialogResponse, к оператору выбора switch, добавляем следующий код
PHP:
		case LOG_DIALOG:
		{
			new wrong_pass[8];
			new load_query[512];
			if(!response)
			{
				/*
					Тут необходимо указать действие при отказе ввода
					я для наглядности поставлю кик
				*/
				Kick(playerid);
				return 1;
			}
			if(strlen(pData[playerid][pPassword]) < MIN_PASS_LENGTH || strlen(pData[playerid][pPassword]) > MAX_PASS_LENGTH)
			{
				ShowPlayerDialog(playerid, LOG_DIALOG, DIALOG_STYLE_INPUT, "Авторизация", "Неправильная длинна пароля! Попробуйте ещё раз", ">>", "Выход");
				return 1;
			}
			if(!strcmp(pData[playerid][pPassword], inputtext, true))
			{
				mysql_format(MySQL, load_query, 512, "SELECT * FROM `"TABLE_ACCOUNTS"` WHERE `Nickname` = '%s' AND `Password` = '%s'", pData[playerid][pName], pData[playerid][pPassword]);
				mysql_tquery(MySQL, load_query, "LoadPlayerAccount", "d", playerid);
				SendClientMessage(playerid, -12, "Идет загрузка данных игрока...");
			}
			else
			{
				WrongPass[playerid] ++;
				if(WrongPass[playerid] > 2) //если больше двух ошибок, то всё!!!
				{
					/*
						Тут необходимо указать действие при трёхкратном введении неправильного пароля
						я опять же для наглядности поставлю кик
					*/
					Kick(playerid);
					return 1;
				}
				ShowPlayerDialog(playerid, LOG_DIALOG, DIALOG_STYLE_INPUT, "Авторизация", "Вы ввели неправильный пароль!!! Попробуйте ещё раз", ">>", "Выход");
				format(wrong_pass, 8, "~r~%d/3", WrongPass[playerid]);
				GameTextForPlayer(playerid, wrong_pass, 3000, 6);
			}
			return 1;
		}
		case REG_DIALOG:
		{
			switch(listitem)
			{
				case 0: //правила
				{
					if(RegData[playerid][pAcceptRules] > 1) //если прочитал все страницы правил
					{
						SendClientMessage(playerid, -1, "Вы ознакомилены с правилами");
						ShowRegisterDialog(playerid);
						return 1;
					}
					ShowPlayerDialog(playerid, REG_DIALOG+1, DIALOG_STYLE_MSGBOX, "Правила сервера", "Правило #1 Не наруйшай правил\nПравило #2 Будь паинькой", ">>", "");
					RegData[playerid][pAcceptRules] = 1; //игрок посмотрел первую страницу
				}
				case 1: //пол персонажа
				{
					ShowPlayerDialog(playerid, REG_DIALOG+2, DIALOG_STYLE_MSGBOX, "Выбор пола персонажа", "Выберите пол вашего персонажа", "Мужской", "Женский");
				}
				case 2:
				{
					ShowPlayerDialog(playerid, REG_DIALOG+3, DIALOG_STYLE_INPUT, "Реферал", "Введите имя игрока, который пригласил вас на сервер", ">>", "Назад");
				}
				case 3:
				{
					ShowPlayerDialog(playerid, REG_DIALOG+4, DIALOG_STYLE_INPUT, "Пароль", "Придумайте пароль для вашего аккаунта", ">>", "Назад");
				}
				case 4: //завершение регистрации
				{
					if(RegData[playerid][pAcceptRules] < 2) return SendClientMessage(playerid, -1, "Ошибка: Вы не ознакомились с правилами сервера!"), ShowRegisterDialog(playerid);
					if(!RegData[playerid][pSex]) return SendClientMessage(playerid, -1, "Ошибка: Вы не указали пол персонажа!"), ShowRegisterDialog(playerid);
					if(strlen(RegData[playerid][pPassword]) < MIN_PASS_LENGTH || strlen(RegData[playerid][pPassword]) > MAX_PASS_LENGTH) return SendClientMessage(playerid, -1, "Ошибка: Вы не указали пароль!"), ShowRegisterDialog(playerid);

					new add_db[512]; //замените этот массив на свой массив, который вы используете для запросов, если он есть

					/* Переносим введенные данные в конструкцию для хранения информации об аккаунте */

					format(pData[playerid][pReferal], 64, RegData[playerid][pReferal]);
					format(pData[playerid][pPassword], 64, RegData[playerid][pPassword]);
					RegData[playerid][pSex] = pData[playerid][pSex];

					/* Отправляем запрос на добавление аккаунта в базу */

					mysql_format(MySQL, add_db, 512, "INSERT INTO `"TABLE_ACCOUNTS"` (`Nickname`, `Password`, `Level`, `Sex`, `Referal`, `Admin`) VALUES ('%s', '%s', 1, '%d', '%s', 0)", pData[playerid][pName], pData[playerid][pPassword], pData[playerid][pSex], pData[playerid][pReferal]);
					mysql_pquery(MySQL, add_db, "OnPlayerRegister", "d", playerid);

					ResetRegData(playerid); //обнуляем даныне регистрации

					/*
						Запрос на внесение аккаунта в базу добавлен.
						В паблике OnPlayerRegister внесутся стандартные данные и произойдет спавн игрока
					*/
				}
			}
			return 1;
		}
		case REG_DIALOG+1:
		{
			if(RegData[playerid][pAcceptRules] > 1)
			{
				SendClientMessage(playerid, -1, "Вы успешно ознакомились с правилами сервера");
				ShowRegisterDialog(playerid);
				return 1;
			}
			ShowPlayerDialog(playerid, REG_DIALOG+1, DIALOG_STYLE_MSGBOX, "Правила сервера", "Правило #3 Не флуди\nПравило #4 Не вреди", ">>", "");
			RegData[playerid][pAcceptRules] = 2;
			return 1;
		}
		case REG_DIALOG+2:
		{
			if(response) RegData[playerid][pSex] = 1;
			else RegData[playerid][pSex] = 2;
			SendClientMessage(playerid, -1, "Пол успешно установлен");

			ShowRegisterDialog(playerid);
			return 1;
		}
		case REG_DIALOG+3:
		{
			if(!response) return ShowRegisterDialog(playerid);

			if(strlen(inputtext) < 4 || strlen(inputtext) > 32)
			{
				SendClientMessage(playerid, -1, "Имя реферала должно содержать минимум 3 и максимум 32 символа");
				ShowPlayerDialog(playerid, REG_DIALOG+3, DIALOG_STYLE_INPUT, "Реферал", "Введите имя игрока, который пригласил вас на сервер", ">>", "Назад");
				return 1;
			}
			format(RegData[playerid][pReferal], 32, inputtext);
			SendClientMessage(playerid, -1, "Реферал успешно указан");

			ShowRegisterDialog(playerid);
			return 1;
		}
		case REG_DIALOG+4:
		{
			/*
				Тут вы можете поизвращаться над паролем: добавляйте мд5, проверяйте пароль на символы/кириллицу и т.д. и т.п. на ваш взгляд
				Это базовая версия системы регистрации, поэтому я не буду добавлять никаких проверок, а оставлю это удовольствие вам! :)
			*/
			if(strlen(inputtext) < MIN_PASS_LENGTH || strlen(inputtext) > MAX_PASS_LENGTH)
			{
				SendClientMessage(playerid, -1, "Недопустимая длинна пароля");
				ShowPlayerDialog(playerid, REG_DIALOG+4, DIALOG_STYLE_INPUT, "Пароль", "Придумайте пароль для вашего аккаунта", ">>", "Назад");
				return 1;
			}
			format(RegData[playerid][pPassword], 64, inputtext);
			SendClientMessage(playerid, -1, "Пароль успешно указан");

			ShowRegisterDialog(playerid);
			return 1;
		}
Если вы используете оператор условия if, то это легко исправить заменив case REG_DIALOG... на if(dialogid == REG_DIALOG...)

С кодом справились, переходим к аспектам.

- Вы можете включать/отключать шифрование пароля в переключателе меняя значение идендификатора ENCRYPT_PASS на 1 и 0 соответственно
- В список можно легко добавить новый пункт. Для этого в энуменатор regdata нужно добавить новую переменную, а в диалог регистрации дописать название пункта по изложенному примеру
- Вы можете добавлять сколько угодно страниц правил просто меняя значение последней в условиях в диалоге REG_DIALOG+1

Ссылка на чистый мод с одной только регистрацией:
Ссылка на virustotal, если вы боитесь хацкерафф:

На этом всё :)
И по традиции, если у вас возникли вопросы или предложения, пишите в эту тему, либо мне в ЛС.
Автор - я.
На сторонних pawn-порталах эта тема может быть продублирована мной под ником Atu.
В этой системе нет md5 шифрования, нет проверок на кириллицу и т.п., но это всё можно легко добавить, используя мануалы из интернета, либо я могу в персональном порядке на платной основе добавить в систему то, что вам понадобиться. Держу связь через ЛС, либо через свою страничку ВК: vk.com/pwnblog

Всем приятной работы! :)
 
Последнее редактирование:
Сверху Снизу