Um método bom para criar um Sistema de Registro e Login que tava desenvolvido aqui no meu pastebin. Resolvi compartilhar um deles para estrear o Portal SA-MP e ajudar muitos que deseja começar um projeto em DOF2 e aprender um método bom para fazer um sistema de registro e login.
Informações do Salvamento
Lançamento: v0.1 (28 Setembro 2020):
- Senha
- IP
- Dinheiro
- Level
- Skin
- Interior
- VirtualWorld
- Estrelas de Procurado
Atualização: v0.2 (30 Junho 2021):
+ Salvamento Fome
+ Salvamento Sede
+ Salvamento Admin
+ Salvar última posição
+ Mensagens após spawnar
+ Tentativas de acertar a senha
Atualização: v0.3 (29 Março 2022):
+ Salvamento de Vida
+ Salvamento de Colete
+ Melhorias em Resetar as Variáveis
Atualização: v0.4 (11 Maio 2022):
+ Link de imagens atualizado
+ Código melhorado na escolha de sexo
+ Adicionado Interpolate Camera na entrada
+ Remoção dos botões "<<", ">>" e "Spawn" na entrada
Prints / Local de Salvamento
» Prints do Sistema (Imgur) » Para funcionar 100% você precisa criar uma pasta chamada "Contas" em sua pasta "scriptfiles".
Inserido por: Raayzeck - 28/09/2020 21:39 - Fórum: Includes
- Sem Respostas
PreviewModelDialog.inc
Versão: 4.6 || Ultima atualização: 29 de Março, 2018
Esta include apresenta a você um novo estilo de diálogo: "DIALOG_STYLE_PREVIEW_MODEL". Um dialog parecido com o normal, mas com modelos de visualização em forma de lista!
Funcionalidades:
Sem limites de tamanho Por causa do Pawn-Memory, todos os itens de lista são alocados dinamicamente, o que significa que você pode ter quantos itens de lista quiser!
Sem pré-alocação de memória A memória para armazenar os dados dos itens do diálogo do jogador é feita durante o tempo de execução, sem memória pré-alocada de todo! Portanto, não há grandes tamanhos do arquvio .amx!
Visualização grande o suficiente Um modelo de visualização razoavelmente grande e intratável, listitem textdraw / botão, permitindo que você visualize os modelos com clareza!
Botões de rotação e zoom Você pode girar o ângulo Z de cada item da lista enquanto visualiza a caixa de diálogo, este é um recurso do jogo acessado pelo jogador que visualiza a caixa de diálogo.Da mesma forma, você tem outros botões para aumentar / diminuir o zoom do modelo.
Uma barra de rolagem perfeita A barra de rolagem é feita de Sprite (LD_SPAC: WHITE) permitindo uma medição perfeita do comprimento de acordo com o tamanho da página!
Códigos GameText em itens de lista Como a caixa de diálogo é feita com desenhos de texto puros, você pode usar códigos de etiqueta (por exemplo, ~ n ~ - linha de mudança ou ~ r ~ - cor vermelha) no texto de etiqueta do modelo de visualização.
Hooked ShowPlayerDialog Suporte a função de diálogo samp "ShowPlayerDialog" e você pode lidar com a resposta em "OnDialogResponse". Verifique os exemplos de como usar.Adicionando rotação / cor personalizadaVocê pode definir a rotação de cada modelo usando um padrão de string simples enquanto faz a lista da caixa de diálogo.
Exemplo:
Iremos fazer a lista de três carros e setar a rotação (0.0, 0.0, -50.0, 1.0).
Aviso: A string destacada entre colchetes, é como você define a rotação.
Exemplo 2:
Aqui iremos modificar, primeiramente, a rotação do carro (0.0, 0.0, 0.0, 0.75) e também as cores (0, 6).
Aviso: Os demais modelos terão valores padrão para rotação (0,0, 0,0, -45,0, 1,0) e cores (-1, -1).
- Adicionada mensagem de que o terminal kdff não conseguiu ler os caminhos citados na linha de comando.
v0.2.5a DEZ/2018
- Expandida a função Easy Color do kdffgui.exe. Você poderá adicionar iluminação direcional simples (de uma única fonte de luz) ao dff sem ter que importar o modelo para o blender ou 3dsmax.
v0.2.0b DEZ/2017
- O kdff ainda tentará importar as cores noturnas dos vértices, mesmo quando as contagens de vértices do modelo importado não corresponderem.
v0.2.0a DEZ/2017
- Adicionado o parâmetro -v no terminal do kdff.exe para importar as cores do vértice noturno de outro dff.
- Adicionado o botão Import NV ao kdffgui.exe que tem a mesma função do -v do terminal do kdff.exe. As cores do vértice noturno são importadas das cores do vértice do mesmo modelo.
- Adicionado o botão Easy Colors ao kdffgui.exe. Todas as cores do vértice são definidas para uma única cor. A primeira cor é a que é apresentada no dia, a segunda cor é a apresentada a noite.
v0.1.1e NOV/2017
- Ao gerar a colisão não irá falhar quando a geometria possuir várias texturas atribuídas a um material.
- Mais tipos de dff podem ser lidos e não causam mais falhas na geração da colisão (.col).
v0.1.1d NOV/2017
- Corrigido bug que um dff corrompido seria gerado ao atachar um .col e um .dff contendo pre-light.
v0.1.1c NOV/2017
- Adicionado o parâmetro -p no terminal do kdff.exe
Você provavelmente já lidou com jogadores dessincronizados antes e sabe o quão problematico pode ser, especialmente por questão de falsos-positivos em sistemas de anti-cheat.
Vamos supor que seu anti-cheat expulsa jogadores se a arma não for dada pelo servidor. Se você fosse disarmar um jogador dessincronizado, suas armas não seriam removidas e o mesmo seria uma vítima de falso-positivo, sendo expulso por algo que não fez.
Em geral, você não pode "spawnar", mudar a vida/colete por funções, teleportar, dar/remover armas, mudar a munição, etc desses jogadores. Isso ocorre por que jogadores dessincronizados não reagem a alguns RPCs (chamadas de procedimento remoto) mandados pelo servidor, porém, client messages (SendClientMessage) e game texts ainda funcionam.
A callback OnPlayerUpdate
Esta callback ainda é executada. Isso por que esses jogadores ainda mandam pacotes de sincronização para o servidor, e esse é o motivo pelo qual você ainda pode vê-los movendo/disparando e interagindo com o servidor e possivelmente com outros jogadores.
Jogadores dessincronizados não reagem a alguns RPCs, como previamente dito. Eles ainda podem andar por ai, mandar comandos para o servidor, conversar, matar outros jogadores, etc, porém, eles também notam problemas em seu fim. Existem dois RPCs para fazer o processo de stream in/out com veículos e jogadores, e esses são alguns dos RPCs que não vão ser processados no cliente do jogador dessincronizado, então, outros jogadores não vão passar por esse processo, e isso significa que, jogadores que deveriam passar pelo processo de stream-out, não seram removidos do jogo, e aqueles que deveriam passar pelo processo de stream-in não vão ser adicionados, não se tornando visíveis no jogo do jogador dessincronizado, isso por que seus player-peds ainda não foram criados e não vão ser. Jogadores que deveriam ser removidos não teram seus player-peds destruidos e vão permanecer, porém, não serão sincronizados com o jogador novamente, isso por que o servidor já reconheçe que esses jogadores não estão na sua area de stream-in, não enviando os pacotes de sincronização para o jogador, então esses outros jogadores são vistos como se estivessem AFK, o que não é a realidade.
Os chamados de "laggers" ainda reagem a essas atualizações, mas ambos os casos são diferentes e não devem ser confundidos. De qualquer forma, eles também são vítimas de falsos-positivos e tem grandes chances de serem dessincronizados em algum momento.
Como detectar?
Agora que você sabe que esses jogadores não reagem a alguns RPCs, existem algumas coisas que você poderia tentar. Eu pessoalmente gosto e uso esta forma para saber de jogadores possivelmente dessincronizados (Leve em consideração que esta é apenas uma parte de meu sistema para que você tenha uma idéia de como funciona, não é algo pronto para você copiar e colar em seu script):
//Utilizando IsPlayerSynced{playerid} em algum lugar...
Como isso funciona exatamente? Este pequeno sistema simplesmente muda a munição na slot 0 (punhos/soco inglês) entre 1 e 0 (antes que você me pergunte, a munição de armas brancas não importa, então não podem ser removidas mudando sua munição para 0), que não é notado pelos jogadores. Já que jogadores dessincronizados não podem ter sua munição mudada de alguma forma pelo servidor, ela continuara sendo a mesma, e é assim que funciona.
Por que a callback OnPlayerUpdate? Como previamente dito, jogadores dessincronizados ainda mandam pacotes de sincronização para o servidor, então a callback continua sendo executada. Logo, fazer a verificação ai é bom, especialmente por que jogadores AFK não seram "marcados" como dessincronizados, não interferindo com sua verificação.
O que fazer após confirmado?
Você pode expulsar o jogador com um aviso dizendo para conectar novamente. Por que? Por que mesmo que seu servidor não se constitua de sistemas onde jogadores dessincronizados são potenciais vítimas de falsos-positivos, isso só resulta em confusão e geralmente em denúncias falsas por parte de outros jogadores, especialmente pelo fato de que pessoas que deveriam passar pelo processo de stream-in, não vão aparecer no jogo do jogador dessincronizado, sendo impossível causar dano, pois o mesmo não vê esses jogadores e não vai registrar o dano por sua parte em seu cliente.
O Easy Project é um script/gamemode para San Andreas Multiplayer sem modalidade de jogo com objetivo único de auxiliar programadores nesta área a desenvolverem conceitos e saberes utilizando como assistência um código limpo e eficaz.
Desenvolvi este projeto pois salvamento de dados em arquivos de texto, principalmente utilizando a biblioteca do DOF2, ainda é comumente aplicado. Vale ressaltar que não foi utilizado acentuações e/ou caracteres especiais devido a não compatibilidade com a plataforma android.
As imagens do projeto estão no repositório, além disso, as bibliotecas utilizadas estão no topo do gamemode. Favor realizar a instalação de todas para que o servidor funcione normalmente.
Sistemas:
O Projeto contempla sistemas como;
Criação e salvamento de dados do jogador (Senha, Admin, Score, Money, Gênero, Skin, Última posição, Interior e VirtualWorld).
Escolha de Skin de acordo com o gênero escolhido (Masculino e Feminino).
Pequeno sistema administrativo com certos comandos.
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 youtube como instalar corretamente, mas não tem mistério.
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.
Código PHP:
#include <a_samp> #include <a_mysql>
Definiremos algumas coisas
Código PHP:
#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.
Código PHP:
#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.
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.
Código PHP:
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.
Código PHP:
// 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.
Código PHP:
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
Código PHP:
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; }
Código PHP:
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.
Código PHP:
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.
Código PHP:
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.
Código PHP:
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
Código PHP:
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.
Código PHP:
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.
Código PHP:
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; }
//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.
Basicamente é isso, um tutorial um pouco extenso, de um jeito que eu considero fácil de entender, caso você tenha se confundi em alguma parte desse tutorial, comente pra mim tirar suas duvidas.
Caso algo no tutorial esteja errado, me avise pra mim consertar.
Ola Pessoal Do Portal Sa-mp Estou A Procura De um Sistema De Bindagem De Veiculos , Estou Tentando fazer Uma Oficina , Caso Alguem Possa me ajudar Ficarei Grato Obg Pela Atencao !
Muitas pessoas podem ter dúvidas de como usar a include dof2. Nesse tutorial estarei tirando esse misticismo de que é algo complicado, como vemos em muitas comunidade de SA-MP. Após ler e entender esse tutorial, você estará apto a desenvolver qualquer tipo de sistema que queira armazenar dados.
O que é
DOF2 é uma include responsável por gerenciamento de dados armazenados em arquivos. Ele é muito utilizado em sistemas de registro, salvamento, empresas, etc...
Salve o arquivo na pasta pawno/includes com o nome de DOF2.inc. DOF2 em maiúsculo e a extensão .inc.
Na parte de includes no seu gamemode, normalmente no topo, inclua a include inserindo o código abaixo:
Code:
Código PHP:
#include DOF2
Pronto. Seguindo esses 3 passos você tem o DOF2 instalado e pronto para ser usado.
Funcionalidade
O sistema de armazenamento e identificação dos dados em DOF2 funciona no formato: CHAVE=VALOR
CHAVE: é o identificador de cada valor. Você não pode ter chaves com o mesmo nome. Você sempre se referencia a ela quando quer recuperar algum valor.
VALOR: é o valor propriamente dito.
Você pode imaginar esse sistema como um sistema de variável aonde a chave é o nome da variável e o valor é o valor da variável.
PS: Vocês podem encontrar muito no cabeçalho das funções a palavra: key[], que se refere a chave;
Comandos básicos
Vamos agora entrar na parte dos comandos básicos. Nesse tutorial irei ensinar a vocês o uso dos comandos que acho que vocês tem a maior chance de usar. Existem diversos outros comandos, todavia, não os acho pertinentes.
DOF2_CreateFile(file[],password[]="")
Cria um arquivo.
DOF2_SetString(file[], key[], tag[]="") DOF2_SetInt(file[], key[], tag[]="") DOF2_SetFloat(file[], key[], tag[]="")
Comando que inserem um valor no arquivo. Literal, numérico, fracionário e booleano (string, int, float e boolean).
Assim chegamos na parte final do nosso tutorial sobre DOF2. Com esse conteúdo vocês estão aptos a construir qualquer sistema de armazenamento de informações que bem desejarem.