[SIZE="6"]Base d'un système d'enregistrement avec Mysql R39-3 & Whirlpool[/SIZE]
Ce tutoriel n'explique pas directement comment fonctionne le plugin mysql de BlueG & Maddinat0r, mais quelque chose d'un peu plus simple sur un système d'enregistrement.
[SIZE="3"]Niveau de difficulté : Moyen[/SIZE][INDENT]
[SIZE="3"]Requis :[/SIZE][/INDENT]
- Une connaissance des bases du Pawn
- Une connaissance des bases du SQL
- De la logique
- [URL="https://github.com/pBlueG/SA-MP-MySQL/releases/tag/R39-3"]Plugin Mysql R39-3[/URL]
- [URL="http://forum.sa-mp.com/showthread.php?t=65290"]Plugin Whirlpool[/URL]
[INDENT]
[SIZE="3"]Fonctionnement :[/SIZE]Un système très simple, où le joueur se connecte pour la première fois, s'enregistre et se connecte.
Nous utiliserons le cache dans ce tutoriel et nous hacherons le mot de passe des joueurs.
Je mettrai quelque bonus à la fin pour que vous constatiez que ce genre de base fonctionne.
[SIZE="3"]Théorie et Pratique :[/SIZE]Avant d'commencer, voici le code SQL de la table pour ce tutoriel :
- Code:
-
CREATE TABLE IF NOT EXISTS `Joueurs` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Pseudo` varchar(24) NOT NULL,
`MotDePasse` varchar(128) NOT NULL,
`AdminLevel` int(11) NOT NULL,
`Skin` int(11) NOT NULL,
`Tuer` int(11) NOT NULL,
`Mort` int(11) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Nous partirons d'une page blanche pour ce tutoriel, tout d'abord, nous allons placer toutes les callbacks que nous utiliserons :
[php]#include <a_samp> // La base pour que les callbacks et fonctions soient reconnues par le compilateur
#include <a_mysql> // Les natives pour utiliser les fonctions de cache mysql
native WP_Hash(buffer[], len, const str[]); // La native Whirlpool
public OnGameModeInit() // Nous l'utiliserons pour établir la connexion à la base de donnée
{
return 1;
}
public OnGameModeExit() // Nous l'utiliserons pour établir la déconnexion de la base de donnée
{
return 1;
}
public OnPlayerConnect(playerid) // Nous l'utiliserons pour récupérer seulement le pseudo du joueur
{
return 1;
}
public OnPlayerDisconnect(playerid, reason) // Nous l'utiliserons pour sauvegarder les informations et les ré-initialisées
{
return 1;
}
public OnPlayerRequestClass(playerid, classid) // Nous l'utiliserons pour établir l'appel de la requête threadée
{
return 1;
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) // Nous l'utiliserons pour gérer les dialogues lors que l'inscription et la connexion du joueur
{
return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
public OnPlayerDeath(playerid, killerid, reason) // Bonus
{
return 1;
}
//--------------------------------------------------------------------
public OnPlayerText(playerid, text[]) // Bonus
{
return 1;
}
//--------------------------------------------------------------------
public OnPlayerCommandText(playerid, cmdtext[]) // Bonus
{
return 0;
}[/php]
Nous allons commencer en créer toutes nos variables et énumération :
[php]#include <a_samp>
#include <a_mysql>
new
mysql; // La variable qui stockera le pointeur de la connexion avec la base de donnée
native WP_Hash(buffer[], len, const str[]);
enum Joueur_Informations
{
IDSql, // ID Mysql
bool:Logguer, // Si le joueur est loggué ou pas
Pseudo[MAX_PLAYER_NAME+1], // Le pseudo du joueur
Mdp[129], // Le mot de passe
Adminlevel, // Son niveau admin
Skin, // Son skin
Tuer, // Son nombre de kills
Mort // Son nombre de morts
}
new
JoueurInfo[MAX_PLAYERS][Joueur_Informations];
[/php]
Now, j'vais vous passer quelque macro dont on aura besoin pour ce système :
[php]#include <a_samp>
#include <a_mysql>
new
mysql;
#define MYSQL_HOST ""
#define MYSQL_USER ""
#define MYSQL_DB ""
#define MYSQL_PASSWORD ""
// Les informations de votre base de donnée
#define GetName(%0) JoueurInfo[%0][Pseudo]
// Macro permettant de récupérer le pseudo du joueur
#define IsPlayerLogguer(%0) (JoueurInfo[%0][Logguer])
// Macro permettant de savoir si le joueur s'est loggué
#define DIALOG_REGISTER 0
#define DIALOG_CONNECTION 1
// Les IDs des dialogs
native WP_Hash(buffer[], len, const str[]);
enum Joueur_Informations
{
IDSql,
bool:Logguer,
Pseudo[MAX_PLAYER_NAME+1],
Mdp[129],
Adminlevel,
Skin,
Tuer,
Mort
}
new
JoueurInfo[MAX_PLAYERS][Joueur_Informations];[/php]
Très bien, la base de la base est faite, on va attaquer la connexion et la déconnexion à la base de donnée.
[php]public OnGameModeInit()
{
mysql = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_DB, MYSQL_PASSWORD);
// Connexion à la base de donnée
return 1;
}
public OnGameModeExit()
return mysql_close(mysql);
// Déconnexion de la base de donnée[/php]
Récupérons maintenant le pseudo du joueur :
[php]public OnPlayerConnect(playerid)
return GetPlayerName(playerid, JoueurInfo[playerid][Pseudo], MAX_PLAYER_NAME+1);[/php]
So', il va maintenant falloir se concentrer, car si vous ne savez absolument pas comment vous pourriez faire pour la suite, vous risquez d'être perdu!
[php]public OnPlayerRequestClass(playerid, classid)
{
if(IsPlayerLogguer(playerid)) return SpawnPlayer(playerid); // Au cas où le joueur aurait forcé son retour à la sélection des classes et qu'il serait déjà loggué
SetSpawnInfo(playerid, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // Obligatoire, sinon le joueur ne spawnera jamais
TogglePlayerSpectating(playerid, true); // Pour cacher les boutons en bas
new
req[128]; // Tableau dans lequel nous formaterons notre requête SQL
mysql_format(mysql, req, sizeof(req), "SELECT * FROM `Joueurs` WHERE `Pseudo` = '%s' LIMIT 1", GetName(playerid));
// On sélectionne tous les informations par rapport au pseudo du joueur dans notre table "Joueurs"
mysql_tquery(mysql, req, "Verification", "i", playerid);
// On exécute notre requête et on ira chercher nos informations dans notre thread "Verification"
return 1;
}[/php]
Vérifions maintenant si le joueur possède ou non un compte sur votre serveur :
[php]forward Verification(playerid);
public Verification(playerid)
{
if(cache_get_row_count()) // Si le compte a été trouvé
{
new
str[MAX_PLAYER_NAME+9] = "Bonjour ";
strcat(str, GetName(playerid)); // "Bonjour {Pseudo}"
// On lui affiche le dialogue de connexion
return ShowPlayerDialog(playerid, DIALOG_CONNECTION, DIALOG_STYLE_INPUT, str, "Entre ton mot de passe :", "Connexion", "Quitter");
}
// Sinon on lui affiche le dialogue d'enregistrement
return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_INPUT, "Enregistrement", "Pour t'inscrire entre un mot de passe de plus de 4 caractères.", "Enregistrer", "Quitter");
}[/php]
On va
[php]public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
switch(dialogid) // On scanne la valeur de dialogid
{
case DIALOG_REGISTER: // Si dialogid contient la valeur de notre macro DIALOG_REGISTER
{
if(!response) return Kick(playerid); // Si le joueur a cliqué sur "Quitter" on le kick
if(strlen(inputtext) < 5) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_INPUT, "Enregistrement", "Pour t'inscrire entre un mot de passe de plus de 4 caractères.", "Enregistrer", "Quitter");
// Si le mot de passe entré est inférieur à 5 caractères
new
mdphash[129], // Tableau qui stockera le mot de passe hashé
req[256]; // Tableau qui stockera la requête SQL
WP_Hash(mdphash, sizeof(mdphash), inputtext); // On hashe le mot de passe et on le stocke dans "mdphash"
mysql_format(mysql, req, sizeof(req), "INSERT INTO `Joueurs` (Pseudo, MotDePasse) VALUES ('%s', '%s')", GetName(playerid), mdphash);
// On formate la requête SQL en y insérant le pseudo et le mot de passe
mysql_tquery(mysql, req);
// On exécute la requête sans appeler de fonctions publiques
new
str[MAX_PLAYER_NAME+9] = "Bonjour ";
strcat(str, GetName(playerid)); // "Bonjour {Pseudo}"
// Il s'est inscrit correctement, il doit maintenant se connecter
return ShowPlayerDialog(playerid, DIALOG_CONNECTION, DIALOG_STYLE_INPUT, str, "Ton compte a bien été enregistré, entre de nouveau ton mot de passe :", "Connexion", "Quitter");
}
}
return 1;
}[/php]
Passons à la connexion :
[php]public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
switch(dialogid) // On scanne la valeur de dialogid
{
case DIALOG_CONNECTION: // Si dialogid contient la valeur de notre macro DIALOG_CONNECTION
{
if(!response) return Kick(playerid); // Si le joueur a cliqué sur "Quitter" on le kick
if(strlen(inputtext) < 5) // Si le mot de passe entré est inférieur à 5 caractères
{
new
str[MAX_PLAYER_NAME+9] = "Bonjour ";
strcat(str, GetName(playerid));
return ShowPlayerDialog(playerid, DIALOG_CONNECTION, DIALOG_STYLE_INPUT, str, "Entre ton mot de passe :", "Connexion", "Quitter");
}
WP_Hash(JoueurInfo[playerid][Mdp], 129, inputtext); // On hashe le mot de passe entré et on le place dans notre table "Mdp"
new
req[128]; // Tableau dans lequel on formate notre requête SQL
mysql_format(mysql, req, sizeof(req), "SELECT * FROM `Joueurs` WHERE `Pseudo` = '%s'", GetName(playerid));
// On sélectionne toutes les informations par rapport au pseudo du joueur
return mysql_tquery(mysql, req, "Connection", "i", playerid);
// On Exécute la requête et on appelle la fonction publique "Connection" avec comme paramètre l'id du joueur
}
}
return 1;
}[/php]
On va vérifier maintenant si le joueur a tapé le bon mot de passe et lui attribuer ses informations.
[php]forward Connection(playerid);
public Connection(playerid)
{
new
mdp[129]; // Tableau dans lequel on va stocker le mot de passe dans la base de donnée
cache_get_field_content(0, "MotDePasse", mdp); // On récupère me mot de passe et on le stocke dans la variable "mdp"
if(strcmp(mdp, JoueurInfo[playerid][Mdp], true) == 0) // On vérifie que les mots de passe sont identiques
{
JoueurInfo[playerid][IDSql] = cache_get_field_content_int(0, "ID");
JoueurInfo[playerid][Adminlevel] = cache_get_field_content_int(0, "AdminLevel");
JoueurInfo[playerid][Skin] = cache_get_field_content_int(0, "Skin");
JoueurInfo[playerid][Tuer] = cache_get_field_content_int(0, "Tuer");
JoueurInfo[playerid][Mort] = cache_get_field_content_int(0, "Mort");
JoueurInfo[playerid][Logguer] = true;
// On récupère toutes les informations
// On retourne la fonction en désactivant le mode spectateur, ça fera spawn le joueur
return TogglePlayerSpectating(playerid, false);
}
// Si le mot de passe n'était pas bon, la suite sera exécutée
new
str[MAX_PLAYER_NAME+9] = "Bonjour ";
strcat(str, GetName(playerid)); // "Bonjour {Pseudo}"
// On averti le joueur dans le dialogue que le mot de passe n'est pas bon et on lui propose de retaper son mot de passe
return ShowPlayerDialog(playerid, DIALOG_CONNECTION, DIALOG_STYLE_INPUT, str, "Mot de passe fail\n\nEntre ton mot de passe :", "Connexion", "Quitter");
}[/php]
On finit par la sauvegarde des informations lorsque le joueur se déconnecte :
[php]public OnPlayerDisconnect(playerid, reason)
{
new
req[128]; // Le tableau dans lequel nous aurons notre requête SQL
// On update les informations du joueur par rapport à son ID dans la base de donnée
mysql_format(mysql, req, sizeof(req), "\
UPDATE `Joueurs` SET \
AdminLevel = %d, \
Skin = %d, \
Tuer = %d, \
Mort = %d \
WHERE ID = %d",
JoueurInfo[playerid][Adminlevel],
JoueurInfo[playerid][Skin],
JoueurInfo[playerid][Tuer],
JoueurInfo[playerid][Mort],
JoueurInfo[playerid][IDSql]);
mysql_tquery(mysql, req);
// On exécute la requête
static
array[Joueur_Informations];
JoueurInfo[playerid] = array; // On ré-initialise les informations du joueurs
return 1;
}[/php]
Aller en bonus j'vous ai fait ça car c'est très important pour 2 trus :
[php]public OnPlayerDeath(playerid, killerid, reason)
{
if(killerid != INVALID_PLAYER_ID) JoueurInfo[killerid][Tuer]++; // On incrémente le nombre de tuer, si le killerid est une id valide
JoueurInfo[playerid][Mort]++; // On incrémente le nombre de morts de playerid
return 1;
}
//--------------------------------------------------------------------
public OnPlayerText(playerid, text[])
{
if(!IsPlayerLogguer(playerid)) return 0; // Si le joueur presse F6 lors de l'inscription/connexion, ça l'empêchera d'envoyer un message (merci Vuki)
return 1;
}
//--------------------------------------------------------------------
public OnPlayerCommandText(playerid, cmdtext[])
{
if(!IsPlayerLogguer(playerid)) return 1; // Pareil que OnPlayerText
if(strcmp(cmdtext, "/skinrandom", true) == 0) // Bref vous savez faire une commande avec strcmp....
{
do JoueurInfo[playerid][Skin] = random(300); // On appelle random pour qu'il sorte un nombre entre 0 et 299 qu'on stocke dans la variable "Skin"
while(JoueurInfo[playerid][Skin] == 74); // Si celui-ci est égal à 74, on rappelle le contenu de "do"
return SetPlayerSkin(playerid, JoueurInfo[playerid][Skin]); // On retourne la commande en appelant SetPlayerSkin
}
return 0;
}[/php]
Le code entier, même si j'aime pas faire ça, le voici : [php]#include <a_samp>
#include <a_mysql>
new
mysql;
#define MYSQL_HOST ""
#define MYSQL_USER ""
#define MYSQL_DB ""
#define MYSQL_PASSWORD ""
#define GetName(%0) JoueurInfo[%0][Pseudo]
#define IsPlayerLogguer(%0) (JoueurInfo[%0][Logguer])
#define DIALOG_REGISTER 0
#define DIALOG_CONNECTION 1
#if !defined isnull
#define isnull(%1) \
((!(%1[0])) || (((%1[0]) == '\1') && (!(%1[1]))))
#endif
native WP_Hash(buffer[], len, const str[]);
enum Joueur_Informations
{
IDSql,
bool:Logguer,
Pseudo[MAX_PLAYER_NAME+1],
Mdp[129],
Adminlevel,
Skin,
Tuer,
Mort
}
new
JoueurInfo[MAX_PLAYERS][Joueur_Informations];
public OnGameModeInit()
{
mysql = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_DB, MYSQL_PASSWORD);
return 1;
}
public OnGameModeExit()
return mysql_close(mysql);
public OnPlayerConnect(playerid)
return GetPlayerName(playerid, JoueurInfo[playerid][Pseudo], MAX_PLAYER_NAME+1);
public OnPlayerDisconnect(playerid, reason)
{
new
req[128];
mysql_format(mysql, req, sizeof(req), "\
UPDATE `Joueurs` SET \
AdminLevel = %d, \
Skin = %d, \
Tuer = %d, \
Mort = %d \
WHERE ID = %d",
JoueurInfo[playerid][Adminlevel],
JoueurInfo[playerid][Skin],
JoueurInfo[playerid][Tuer],
JoueurInfo[playerid][Mort],
JoueurInfo[playerid][IDSql]);
mysql_tquery(mysql, req);
static
array[Joueur_Informations];
JoueurInfo[playerid] = array;
return 1;
}
public OnPlayerRequestClass(playerid, classid)
{
if(IsPlayerLogguer(playerid)) return SpawnPlayer(playerid);
SetSpawnInfo(playerid, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
TogglePlayerSpectating(playerid, true);
new
req[128];
mysql_format(mysql, req, sizeof(req), "SELECT * FROM `Joueurs` WHERE `Pseudo` = '%s' LIMIT 1", GetName(playerid));
mysql_tquery(mysql, req, "Verification", "i", playerid);
return 1;
}
forward Verification(playerid);
public Verification(playerid)
{
if(cache_get_row_count())
{
new
str[MAX_PLAYER_NAME+9] = "Bonjour ";
strcat(str, GetName(playerid));
return ShowPlayerDialog(playerid, DIALOG_CONNECTION, DIALOG_STYLE_INPUT, str, "Entre ton mot de passe :", "Connexion", "Quitter");
}
return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_INPUT, "Enregistrement", "Pour t'inscrire entre un mot de passe de plus de 4 caractères.", "Enregistrer", "Quitter");
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
switch(dialogid)
{
case DIALOG_REGISTER:
{
if(!response) return Kick(playerid);
if(isnull(inputtext) || strlen(inputtext) < 5) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_INPUT, "Enregistrement", "Pour t'inscrire entre un mot de passe de plus de 4 caractères.", "Enregistrer", "Quitter");
new
mdphash[129],
req[256];
WP_Hash(mdphash, sizeof(mdphash), inputtext);
mysql_format(mysql, req, sizeof(req), "INSERT INTO `Joueurs` (Pseudo, MotDePasse) VALUES ('%s', '%s')", GetName(playerid), mdphash);
mysql_tquery(mysql, req);
new
str[MAX_PLAYER_NAME+9] = "Bonjour ";
strcat(str, GetName(playerid));
return ShowPlayerDialog(playerid, DIALOG_CONNECTION, DIALOG_STYLE_INPUT, str, "Entre ton mot de passe :", "Connexion", "Quitter");
}
case DIALOG_CONNECTION:
{
if(!response) return Kick(playerid);
if(isnull(inputtext) || strlen(inputtext) < 5)
{
new
str[MAX_PLAYER_NAME+9] = "Bonjour ";
strcat(str, GetName(playerid));
return ShowPlayerDialog(playerid, DIALOG_CONNECTION, DIALOG_STYLE_INPUT, str, "Entre ton mot de passe :", "Connexion", "Quitter");
}
WP_Hash(JoueurInfo[playerid][Mdp], 129, inputtext);
new
req[128];
mysql_format(mysql, req, sizeof(req), "SELECT * FROM `Joueurs` WHERE `Pseudo` = '%s'", GetName(playerid));
return mysql_tquery(mysql, req, "Connection", "i", playerid);
}
}
return 1;
}
forward Connection(playerid);
public Connection(playerid)
{
new
mdp[129];
cache_get_field_content(0, "MotDePasse", mdp);
if(strcmp(mdp, JoueurInfo[playerid][Mdp], true) == 0)
{
JoueurInfo[playerid][IDSql] = cache_get_field_content_int(0, "ID");
JoueurInfo[playerid][Adminlevel] = cache_get_field_content_int(0, "AdminLevel");
JoueurInfo[playerid][Skin] = cache_get_field_content_int(0, "Skin");
JoueurInfo[playerid][Tuer] = cache_get_field_content_int(0, "Tuer");
JoueurInfo[playerid][Mort] = cache_get_field_content_int(0, "Mort");
JoueurInfo[playerid][Logguer] = true;
return TogglePlayerSpectating(playerid, false);
}
new
str[MAX_PLAYER_NAME+9] = "Bonjour ";
strcat(str, GetName(playerid));
return ShowPlayerDialog(playerid, DIALOG_CONNECTION, DIALOG_STYLE_INPUT, str, "Mot de passe fail\n\nEntre ton mot de passe :", "Connexion", "Quitter");
}
//-----------------------------------------------------------------------------------------------------------------------------
public OnPlayerDeath(playerid, killerid, reason)
{
if(killerid != INVALID_PLAYER_ID) JoueurInfo[killerid][Tuer]++;
JoueurInfo[playerid][Mort]++;
return 1;
}
//--------------------------------------------------------------------
public OnPlayerText(playerid, text[])
{
if(!IsPlayerLogguer(playerid)) return 0;
return 1;
}
//--------------------------------------------------------------------
public OnPlayerCommandText(playerid, cmdtext[])
{
if(!IsPlayerLogguer(playerid)) return 1;
if(strcmp(cmdtext, "/skinrandom", true) == 0)
{
do JoueurInfo[playerid][Skin] = random(300);
while(JoueurInfo[playerid][Skin] == 74);
return SetPlayerSkin(playerid, JoueurInfo[playerid][Skin]);
}
return 0;
}[/php]
[/INDENT]
Tutoriel enfin, j'ai très peu écrit entre chaque code montré, car j'ai selon moi, assez expliqué dans les commentaires à chaque ligne.
Si vous constatez qu'il y a un bug, qu'j'ai fait une erreur quelque part ou que vous avez une question car vous ne comprenez pas quelque chose; n'hésitez pas à vous manifestez dans ce topic !
Allez bisous !