Login e Registro em MySQL R41-4
Feito por: Cauezin
Feito por: Cauezin
Este tutorial foi feito por um programador novato para programadores novatos com a função de tentar explicar como funciona e como fazer um sistema de Login/Registro em MySQL R41-4 do jeito mais fácil de entender possível.
LEMBRE-SE FOI FEITO PRA SER UM SISTEMA SIMPLES, SÓ PRA ENTENDER O BÁSICO.
Primeiro de tudo, o que é MySQL?
O MySQL é um sistema de gerenciamento de banco de dados, que utiliza a linguagem SQL como interface.
O que é um banco de dados?
Bancos de dados ou bases de dados são conjuntos de arquivos relacionados entre si com registros sobre pessoas, lugares ou coisas.
Agora a grande pergunta, como utilizar ele para fazer um sistema de login e registro no SA-MP?
Isso por incrível que parece é até bastante simples, provavelmente você pulando os passos, vai achar que é algo extremamente difícil, um bicho de 7 cabeças.
Mas seguindo os passos um a um, corretamente, você vai descobrir que é extremamente simples mexer com esse tipo de gerenciamento de banco de dados.
Agora chega de falação e vamos ao trabalho.
[ 1 ] -> Instalação do servidor
No caso desse tutorial utilizaremos o XAMPP, você pode baixar gratuitamente no link abaixo.
Caso tenha problemas na instalação procure no ******* como instalar corretamente, mas não tem mistério.
XAMPP
[ 2 ] -> Utilizando o servidor e criando o banco de dados e a tabela
Quando você abrir o XAMPP vai se deparar com isso, agora faça a mesma coisa que é feito nessa sequencia de imagens.
[ * ] Agora vamos entender o que você fez
Você executou o XAMPP.
Iniciou os servidores.
Entrou no servidor e criou o banco de dados.
Criou a tabela, dentro do banco de dados.
[ * ] Agora vamos entender a tabela
PHP Code:
- Código:
CREATE TABLE `jogadores`(`pID` int AUTO_INCREMENT PRIMARY KEY,
`pNome` varchar(24),
`pSenha` varchar(24),
`pDinheiro` int(12) DEFAULT 500,
`pScore` int(6),
`pSkin` int(4) DEFAULT 60,
`pPosX` float DEFAULT -2240.9197,
`pPosY` float DEFAULT 252.0263,
`pPosZ` float DEFAULT 35.3203,
`pPosA` float DEFAULT 91.2125)
Você criou a tabela "jogadores" com a coluna do "ID" da conta do player, o "nome" do player, a "senha" do player, o "dinheiro" do player, o "score" do player, a "skin" do player, a coordenada "X" do player, a coordenada "Y" do player, a coordenada "Z" do player, a coordenada "A" do player.
Mas temos coisas diferentes em algumas colunas.
Temos 3 tipos de valores armazenados na nossa tabela
Vou explicar de um jeito leigo, porém é facilmente entendido.
varchar -> números e letras;
int -> números;
float -> números com virgula;
Mas também são de outro tipo
Default -> São colunas com valores padrão, quando você criar uma nova linha, eles vão ter sempre aquele valor.
Ali no caso eu botei o dinheiro do player com default 500, assim quando ele iniciar no servidor, já vai ter $500, a skin default 60, ele já vai começar com a skin id 60 e o mesmo se aplica nas coordenadas, ele vai nascer naquelas coordenadas.
[ 2 ] -> Criação da GM
Você primeiro precisa da include, que pode ser encontrada no link abaixo.
Include
Vamos seguir a linha de raciocínio que o player seguiria ao entrar no servidor pela primeira vez.
Entrar no server -> Se Registrar -> Sair -> Entrar no server -> Logar
Vamos preparar a área.
Primeiro adicionaremos a include na GM.
PHP Code:
- Código:
#include <a_samp>
#include <a_mysql>
Definiremos algumas coisas.
PHP Code:
- Código:
#define HOST "localhost"
o IP do servidor, no caso é hospedado no nosso computador, então localhost ou 127.0.0.1
#define USER "root"
Como estamos hospedando em nosso computador é root.
#define DTBS "samp"
O nome do banco de dados que você criou no inicio.
#define PASS ""
Hospedado no computador não tem senha.
PHP Code:
- Código:
#define Dialog_Login 1
#define Dialog_Registro 2
Dialog do Login e Registro, não é necessário, mas fica melhor.
Teremos que criar a ENUM com as variáveis que utilizaremos no player.
PHP Code:
- Código:
enum PlayerInfos{
pID,
pSenha[24],
pDinheiro,
pScore,
pSkin,
Float:pPosX,
Float:pPosY,
Float:pPosZ,
Float:pPosA,
Abaixo utilizaremos, porém não sera salvo na tabela.
pTentativasLogin,
// Caso ele erre a senha, sera contabilizado.
pTentativasRegistro,
// Caso ele não cumpra o necessário para o registro, sera contabilizado.
bool:pLogado
// Utilizaremos para saber se o player está logado ou não no servidor.
}
new Player[MAX_PLAYERS][PlayerInfos];
//Criaremos uma variável do Player, para utilizar com a ENUM.
new MySQL:ConexaoSQL;
//Essa é para utilizar na parte do MySQL.
As forwards serão criadas adiantadas.
PHP Code:
- Código:
forward VerificarContaSQL(playerid);
// Verifica se ele tem conta registrada
forward InserirDadosSQL(playerid);
// Insere os dados na tabela e cria a conta do player
forward CarregarContaSQL(playerid);
// Carrega a conta do player
forward SalvarContaSQL(playerid);
// Salva a conta do player
forward KickPlayerinTime(playerid);
// Utilizaremos com um timer, pra antes de ser kickado ele saiba o motivo.
Crie a public do KickPlayerinTime e a stock GetPlayerNameEx, serão necessárias logo no início.
Coloque elas no fim da sua GM.
PHP Code:
- Código:
// Ela só tem a função de kickar o player quando acionado.
public KickPlayerinTime(playerid)
{
return Kick(playerid);
}
// Pega o nome do player acionado.
stock GetPlayerNameEx(playerid)
{
static pname[MAX_PLAYER_NAME];
GetPlayerName(playerid, pname, MAX_PLAYER_NAME);
return pname;
}
Primeira coisa que o server precisa é conectar no servidor do banco de dados.
PHP Code:
- Código:
public OnGameModeInit()
{
ConexaoSQL = mysql_connect(HOST,USER,PASS,DTBS);
// Define a variável MySQL como mysql_connect e conecta no servidor do banco de dados.
if(mysql_errno(ConexaoSQL) != 0)
{ // Caso o servidor esteja desligado, você não ter criado o banco de dados ou algum erro, ele não se conecta e te avisa.
print("[MySQL] Falha ao tentar estabelecer conexão com o banco de dados.");
} else {// Caso de tudo certo, ele também te avisa.
print("[MySQL] Sucesso ao conectar com o banco de dados.");
}
return 1;
}
Agora vamos ao quando player entrar no servidor, precisamos verificar se ele tem conta ou não.
PHP Code:
- Código:
public OnPlayerConnect(playerid)
{
new Query[90];
TogglePlayerSpectating(playerid, 1);// Isso daqui é só pra sumir o botão de spawn, tem vários dele espalhado pelo code.
mysql_format(ConexaoSQL, Query, sizeof(Query), "SELECT `pSenha`, `pID` FROM `Jogadores` WHERE `pNome`='%e'", GetPlayerNameEx(playerid));
// Ele seleciona as colunas "pSenha" e "pID" da tabela jogadores AONDE o nome é igual do player.
mysql_tquery(ConexaoSQL, Query, "VerificarContaSQL", "i", playerid);
// Logo depois de selecionar ele aciona a função para Verificar se ele tem conta ou não.
return 1;
}
PHP Code:
- Código:
public VerificarContaSQL(playerid)
{
if(cache_num_rows() > 0) // Se for > 0 , existe uma linha com o nome do player, então ele tem conta.
{
cache_get_value_name(0, "pSenha", Player[playerid][pSenha], 24); // Já puxa a senha pra comparar se é igual a que ele vai digitar no dialog.
ShowPlayerDialog(playerid, Dialog_Login, DIALOG_STYLE_PASSWORD, "Login", "Digite sua senha para entrar em nosso servidor.", "Confirmar", "Sair");
// Abre o dialog pra logar
}else{ // Se não for > 0 , não existe, ele não está registrado.
ShowPlayerDialog(playerid, Dialog_Registro, DIALOG_STYLE_INPUT, "Registro", "Digite uma senha para se registrar em nosso servidor", "Registrar", "Sair");
// Abre o dialog pra se registrar
}
return 1;
}
Vamos começar pelo registro, utilizaremos um sistema de switch, algo básico.
PHP Code:
- Código:
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
new Query[125];
switch(dialogid)
{
case Dialog_Registro:
{
if(!response) // Se ele apertar esc ou na segunda opção, vai ser kickado
return Kick(playerid);
if(strlen(inputtext) < 4 || strlen(inputtext) > 24) // Se o que ele digitou for menor 4 e maior que 24, a senha não sera aceita
{
SendClientMessage(playerid, 0xFF0000AA, "[SERVER] Escolha uma senha entre 4 a 24 caracteres.");
TogglePlayerSpectating(playerid, 1);
ShowPlayerDialog(playerid, Dialog_Registro, DIALOG_STYLE_INPUT, "Registro", "Digite uma senha para se registrar em nosso servidor", "Registrar", "Sair"); // Mostra o dialog para ele tentar de novo.
Player[playerid][pTentativasRegistro]++; // Adiciona +1 ao erro.
} else { // Se a senha for aceitavel, no caso entre 4 a 24 caracteres
TogglePlayerSpectating(playerid, 0); // Tira ele de espectador, agora ele vai entrar no server
mysql_format(ConexaoSQL, Query, sizeof(Query), "INSERT INTO `jogadores`(`pNome`,`pSenha`) VALUES ('%e', '%e')", GetPlayerNameEx(playerid), inputtext);
// Vai inserir na tabela jogares, nas colunas pNome e pSenha os seguintes valores, o nome do player que ele puxou com a stock e o que ele digitou, o inputtext.
mysql_tquery(ConexaoSQL, Query, "InserirDadosSQL", "i", playerid);
// Ele vai executar o comando acima e vai acionar a função de inserir o ID e criar a conta do player
}
if(Player[playerid][pTentativasRegistro] == 3) // Se ele errar mais de 3 vezes vai ser kickado
{
SendClientMessage(playerid, 0xFF0000AA, "[SERVER] Limite de tentativas de registro excedida.");
Player[playerid][pTentativasRegistro] = 0; // Zerar a variável pra caso um outro jogador entre, não começe com 3 na variável
SetTimerEx("KickPlayerinTime", 200, false, "i", playerid); // ele é kickado 200 milisegundos apos isso acontecer, tempo suficiente pra ver a mensagem e ser kickado.
}
}
}
return 1;
}
Vamos agora inserir todos os dados na conta e carregar ela.
PHP Code:
- Código:
public InserirDadosSQL(playerid)
{
new Query[90];
Player[playerid][pID] = cache_insert_id(); // Adiciona o id no player
printf("[MYSQL] Jogador %s registrado como ID %d", GetPlayerNameEx(playerid), Player[playerid][pID]); // Apenas um debug, pra saber se deu tudo certo.
mysql_format(ConexaoSQL, Query, sizeof(Query), "SELECT * FROM jogadores WHERE pID='%i'", Player[playerid][pID]); // Seleciona todas as informações desse player AONDE o id dele é o id dele
mysql_query(ConexaoSQL,Query); // Executa o comando acima
CarregarContaSQL(playerid); // Ele carrega a conta.
return 1;
}
Vamos agora carregar a conta.
PHP Code:
- Código:
public CarregarContaSQL(playerid)
{
Player[playerid][pLogado] = true; // Seta a variável bool, como true, no caso fala como se você tivesse logado.
cache_get_value_int(0, "pID", Player[playerid][pID]); // Carrega o id e armazena nessa variável "Player[playerid][pID]"
cache_get_value_int(0, "pDinheiro", Player[playerid][pDinheiro]); // A mesma coisa nesse e nas outras só que com outra variável
cache_get_value_int(0, "pScore", Player[playerid][pScore]);
cache_get_value_int(0, "pSkin", Player[playerid][pSkin]);
cache_get_value_float(0, "pPosX", Player[playerid][pPosX]);
cache_get_value_float(0, "pPosY", Player[playerid][pPosY]);
cache_get_value_float(0, "pPosZ", Player[playerid][pPosZ]);
cache_get_value_float(0, "pPosA", Player[playerid][pPosA]);
// Ele aplica as informações igame
SetPlayerScore(playerid, Player[playerid][pScore]); // seta o score com a variavel do score
GivePlayerMoney(playerid, Player[playerid][pDinheiro]); // seta o dinheiro com a variavel do dinheiro
// Etc....
SetSpawnInfo(playerid, 0, Player[playerid][pSkin], Player[playerid][pPosX], Player[playerid][pPosY], Player[playerid][pPosZ], Player[playerid][pPosA], 0, 0, 0, 0 ,0, 0);
SpawnPlayer(playerid); //Spawna o player
SetPlayerSkin(playerid, Player[playerid][pSkin]);
// Seta a skin dele, porquê as vezes pode bugar no SetSpawnInfo e aparecer a skin do CJ
return 1;
}
Basicamente essa é a parte de registro, caso você tenha feito tudo certo, quando ligar no seu servidor você vai conseguir se registrar normalmente e jogar normalmente, só que quando sair do servidor, não vai conseguir logar, porque ainda não existe a dialog de login.
Então vamos lá.
Vamos voltar em OnDialogResponse
PHP Code:
- Código:
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
new Query[125];
switch(dialogid)
{
case Dialog_Registro:
{
if(!response) // Se ele apertar esc ou na segunda opção, vai ser kickado
return Kick(playerid);
if(strlen(inputtext) < 4 || strlen(inputtext) > 24) // Se o que ele digitou for menor 4 e maior que 24, a senha não sera aceita
{
SendClientMessage(playerid, 0xFF0000AA, "[SERVER] Escolha uma senha entre 4 a 24 caracteres.");
TogglePlayerSpectating(playerid, 1);
ShowPlayerDialog(playerid, Dialog_Registro, DIALOG_STYLE_INPUT, "Registro", "Digite uma senha para se registrar em nosso servidor", "Registrar", "Sair"); // Mostra o dialog para ele tentar de novo.
Player[playerid][pTentativasRegistro]++; // Adiciona +1 ao erro.
} else { // Se a senha for aceitavel, no caso entre 4 a 24 caracteres
TogglePlayerSpectating(playerid, 0);
mysql_format(ConexaoSQL, Query, sizeof(Query), "INSERT INTO `jogadores`(`pNome`,`pSenha`) VALUES ('%e', '%e')", GetPlayerNameEx(playerid), inputtext);
// Vai inserir na tabela jogares, nas colunas pNome e pSenha os seguintes valores, o nome do player que ele puxou com a stock e o que ele digitou, o inputtext.
mysql_tquery(ConexaoSQL, Query, "InserirDadosSQL", "i", playerid);
// Ele vai executar o comando acima e vai acionar a função de inserir o ID e criar a conta do player
}
if(Player[playerid][pTentativasRegistro] == 3) // Se ele errar mais de 3 vezes vai ser kickado
{
SendClientMessage(playerid, 0xFF0000AA, "[SERVER] Limite de tentativas de registro excedida.");
Player[playerid][pTentativasRegistro] = 0; // Zerar a variável pra caso um outro jogador entre, não começe com 3 na variável
SetTimerEx("KickPlayerinTime", 200, false, "i", playerid); // ele é kickado 200 milisegundos apos isso acontecer, tempo suficiente pra ver a mensagem e ser kickado.
}
}
case Dialog_Login:
{
if(!response) // Se responder a segunda opção ou apertar esc, sera kickado
return Kick(playerid);
if(!strcmp(Player[playerid][pSenha], inputtext, true, 24)) // Compara a senha do player com o que ele digitou
{ // caso esteja certo
TogglePlayerSpectating(playerid, 0); // tira ele de espectador
mysql_format(ConexaoSQL, Query, sizeof(Query), "SELECT * FROM jogadores WHERE pNome='%e'", GetPlayerNameEx(playerid)); // Seleciona tudo aonde o nome dele está
mysql_tquery(ConexaoSQL, Query, "CarregarContaSQL", "i", playerid); // Executa o carregamento de conta
SendClientMessage(playerid, 0x80FF00AA, "[Server] Logado com sucesso."); // E manda uma mensagem falando que ele logou
} else { // Se não for igual
TogglePlayerSpectating(playerid, 1);
SendClientMessage(playerid, 0xFF0000AA, "[SERVER] Senha errada, tente novamente."); // Vai avisar
Player[playerid][pTentativasLogin]++; // Contabilizar +1 erro
ShowPlayerDialog(playerid, Dialog_Login, DIALOG_STYLE_PASSWORD, "Login", "Digite sua senha para entrar em nosso servidor.", "Confirmar", "Sair"); // Mostra a dialog pra ele tentar dnvo
}
if(Player[playerid][pTentativasLogin] == 3) // Caso ele erre 3 vezes
{
SendClientMessage(playerid, 0xFF0000AA, "[SERVER] Limite de tentativas de login excedida."); // Avisa que ele exedeu o limite
Player[playerid][pTentativasLogin] = 0; // Zera a variável pra não gerar conflito
SetTimerEx("KickPlayerinTime", 200, false, "i", playerid); // E kicka ele depois de 200 milisegundos, dando tempo de ver a mensagem
}
}
}
return 1;
}
Agora nós precisamos salvar tudo quando o player deslogar.
PHP Code:
- Código:
public SalvarContaSQL(playerid)
{
if(Player[playerid][pLogado] == false) // Se ele não estiver logado, para ali mesmo
return 0;
new Query[250];
// Usa as variáveis pra pegar os valores in game
Player[playerid][pDinheiro] = GetPlayerMoney(playerid);
Player[playerid][pScore] = GetPlayerScore(playerid);
Player[playerid][pSkin] = GetPlayerSkin(playerid);
GetPlayerPos(playerid, Player[playerid][pPosX], Player[playerid][pPosY], Player[playerid][pPosZ]);
GetPlayerFacingAngle(playerid, Player[playerid][pPosA]);
// Atualiza a tabela jogadores na fila do jogador SETANDO aquelas colunas como %i - interior, número e %f float , número com virgula AONDE está o ID do jogador
mysql_format(ConexaoSQL, Query, sizeof(Query), "UPDATE `jogadores` SET \
`pDinheiro`='%i', \
`pScore`='%i', \
`pSkin`='%i', \
`pPosX`='%f', \
`pPosY`='%f', \
`pPosZ`='%f', \
`pPosA`='%f' WHERE `pID`='%i'", Player[playerid][pDinheiro],
Player[playerid][pScore],
Player[playerid][pSkin],
Player[playerid][pPosX],
Player[playerid][pPosY],
Player[playerid][pPosZ],
Player[playerid][pPosA],
Player[playerid][pID]);
mysql_query(ConexaoSQL, Query); // Executa o comando
printf("[MYSQL] Dados do Jogador %s ID %d salvo com sucesso", GetPlayerNameEx(playerid), Player[playerid][pID]); // Apenas um debug
return 1;
}
Agora temos que aplicar o salvamento.
PHP Code:
- Código:
public OnPlayerDisconnect(playerid, reason)
{
// Se o player estiver logado E a razão do disconnect for 0 ou 1 ou 2, salva a conta e zera os dados para não entrar em conflito com a conta de outro jogador.
if(Player[playerid][pLogado] == true && reason >= 0)
{
SalvarContaSQL(playerid);
ZerarDadosSQL(playerid);
}
return 1;
}
Como zerar
PHP Code:
- Código:
stock ZerarDadosSQL(playerid)
{
Player[playerid][pID] = 0;
Player[playerid][pSenha] = 0;
Player[playerid][pDinheiro] = 0;
Player[playerid][pScore] = 0;
Player[playerid][pSkin] = 0;
Player[playerid][pLogado] = false;
Player[playerid][pTentativasLogin] = 0;
Player[playerid][pTentativasRegistro] = 0;
Player[playerid][pPosX] = 0;
Player[playerid][pPosA] = 0;
Player[playerid][pPosY] = 0;
Player[playerid][pPosA] = 0;
}
//Zere tudo possível, não sabe se precisa ou não? Zera, caso algum outro jogador entre no mesmo momento que ele sair, pode causar um conflito e esse jogador que entrou pegar as informações que você não zerou do player que tinha deslogado.