Salut.Am vazut ca Rimmon a inceput sa posteze cateva tutoriale despre SQLite, asa ca m-am gandit sa postez si eu un tutorial in care va arat cum sa faceti un sistem de inregistrare/logare pe SQLite.Prima data incepeti cu includerile.In cazul de fata, o sa folosesc doar fisierele a_samp.inc, zcmd.inc si YSI\y_ini.inc:
#include " a_samp "
#include " zcmd "
#include " YSI\y_ini "
Acum ca am facut asta, o sa va intrebati de ce am adaugat si y_ini.L-am adaugat fiindca fisierul y_ini contine stock-ul strcpy iar ca sa nu il mai adaug in acest tutorial, am inclus y_ini.Ca sa fie mai usor de explicat si pentru a nu irosi ceva linii, o sa definesc dialog-urile si functile pe care le voi folosi in acest tutorial:
#define SPD ShowPlayerDialog
#define SCM SendClientMessage
#define DIALOG_REGISTER ( 2012 )
#define DIALOG_LOGIN ( 2013 )
#define isnull(%1) ((!(%1[0])) || (((%1[0]) == '\1') && (!(%1[1]))))
Acum ca am facut si asta, trebuie sa facem si datele jucatorului (new-urile):
enum PlayerData
{
Nume [ MAX_PLAYER_NAME ] ,
Bani ,
Scor ,
Ucideri ,
Decese
} ;
new
P_DATA [ MAX_PLAYERS ] [ PlayerData ] ,
bool: Logat [ MAX_PLAYERS ] ,
DB:Conturi
;
Daca a-ti facut toate astea, putem trece la urmatorul pas, acesta fiind pasul care tine de baza de date:
public OnFilterScriptInit ( )
{
new
string [ 756 ]
;
Conturi = db_open ( "Conturi.db" ) ;
strcat ( string , "CREATE TABLE IF NOT EXISTS `Jucatori`" , 756 ) ;
strcat ( string , "(`ID` INTEGER PRIMARY KEY AUTOINCREMENT ,\
`Nume` TEXT ,\
`Parola` TEXT ,\
`Bani` NUMERIC ,\
`Scor` NUMERIC , " , 756 ) ;
strcat ( string , "`Ucideri` NUMERIC ,\
`Decese` NUMERIC ) " , 756 ) ;
db_free_result ( db_query ( Conturi , string ) ) ;
return ( 1 ) ;
}
Daca vreti sa faceti sistemul de inregistrare in modul de joc, schimbati OnFilterScriptInit cu OnGameModeInit.La acest "callback", se va crea baza de date/se va deschide baza de date.Pentru a functiona corect, la final cand modul de joc/scriptul se inchide, trebuie sa inchideti si baza de date:
public OnFilterScriptExit ( )
{
db_close ( Conturi ) ;
return ( 1 ) ;
}
Aici povestea se repeta.Schimbati OnFilterScriptExit cu OnGameModeExit daca aveti "gamemode" si nu "filterscript".Acum ca am facut si baza de date, trebuie sa facem ca atunci cand un jucator se conecteaza, sa ii apara dialogul de inregistrare/logare.Cum facem asta? Simplu.La "callback"-ul OnPlayerConnect trebuie sa verificam daca jucatorul exista in baza de date sau nu:
public OnPlayerConnect ( playerid )
{
new
Query [ 256 ] ,
pNume [ MAX_PLAYER_NAME ] ,
DBResult:Result
;
Logat [ playerid ] = false ;
GetPlayerName ( playerid , pNume , MAX_PLAYER_NAME ) ;
strcpy ( P_DATA [ playerid ] [ Nume ] , DB_Escape ( pNume ) , MAX_PLAYER_NAME ) ;
format ( Query , 256 , "SELECT * FROM `Jucatori` WHERE `Nume` = '%s'" , P_DATA [ playerid ] [ Nume ] ) ;
Result = db_query ( Conturi , Query ) ;
if ( db_num_rows ( Result ) > 0 )
SPD ( playerid , DIALOG_LOGIN , DIALOG_STYLE_PASSWORD , "Logheaza-te" , "Introdu parola in casuta de mai jos:" , "O.K" , "" ) ;
else
SPD ( playerid , DIALOG_REGISTER , DIALOG_STYLE_PASSWORD , "Inregistreaza-te" , "Introdu parola in casuta de mai jos:" , "O.K" , "" ) ;
db_free_result ( Result ) ;
return ( 1 ) ;
}
Acum ca am trecut si de acest pas cu succes, trebuie sa facem ca atunci cand jucatorul se deconecteaza, sa ii se salveze datele.Presupun ca va intrebati "CUM?!" deci am sa va arat cum se poate face asta.Prima data trebuie sa verificam daca jucatorul este logat (de asta se ocupa "bool: Logat"):
public OnPlayerDisconnect ( playerid , reason )
{
if ( Logat [ playerid ] )
{
new
Query [ 256 ]
;
format ( Query , sizeof ( Query ) , "UPDATE `Jucatori` SET `Bani` = '%d' ,`Scor` = '%d' , `Ucideri` = '%d' , `Decese` = '%d' WHERE `Nume` = '%s'"
, GetPlayerMoney ( playerid ) , GetPlayerScore ( playerid ) , P_DATA [ playerid ] [ Ucideri ] , P_DATA [ playerid ] [ Decese ] , P_DATA [ playerid ] [ Nume ] ) ;
db_free_result ( db_query ( Conturi , Query ) ) ;
}
return ( 1 ) ;
}
Acum se salveaza datele jucatorului.Trebuie sa mai facem si "Uciderile" si "Decesele" jucatorului.Pentru a realiza acest lucru, avem nevoie de public-ul (callback-ul) OnPlayerDeath:
public OnPlayerDeath ( playerid , killerid , reason )
{
P_DATA [ playerid ] [ Decese ] ++ ;
if ( killerid != INVALID_PLAYER_ID )
{
P_DATA [ killerid ] [ Ucideri ] ++ ;
}
return ( 1 ) ;
}
Dupa ce am facut si asta, cred ca trebuie sa facem si ultimul pas (pasul final), cel care consta il salvarea si generarea datelor jucatorului.Pentru a realiza asta, ne vom folosi de public-ul OnDialogResponse.Folosindune de acesta, vom mai verifica daca parola introdusa este corecta/gresita sau daca parola introdusa de jucator este "null" adica daca jucatorul nu a introdus nimic:
public OnDialogResponse ( playerid , dialogid , response , listitem , inputtext [ ] )
{
if ( dialogid == DIALOG_REGISTER )
{
if ( !response || isnull(inputtext ) ) return SPD ( playerid , DIALOG_REGISTER , DIALOG_STYLE_PASSWORD , "Inregistreaza-te" , "Introdu parola in casuta de mai jos:" , "O.K" , "" ) ;
new
Query [ 256 ]
;
format ( Query , sizeof ( Query ) , "INSERT INTO `Jucatori` ( `Nume` , `Parola` , `Bani` , `Scor` , `Ucideri` , `Decese` ) VALUES ( '%s' , '%s' , '%d' , '%d' , '%d' , '%d' )"
, P_DATA [ playerid ] [ Nume ] , DB_Escape ( inputtext ) , 0 , 0 , 0 , 0 ) ;
db_free_result ( db_query ( Conturi , Query ) ) ;
SCM ( playerid , -1 , "Te-ai inregistrat cu succes." ) ;
Logat [ playerid ] = true ;
return ( 1 ) ;
}
if ( dialogid == DIALOG_LOGIN )
{
if ( !response || isnull ( inputtext ) ) return SPD ( playerid , DIALOG_LOGIN , DIALOG_STYLE_PASSWORD , "Logheaza-te" , "Introdu parola in casuta de mai jos:" , "O.K" , "" ) ;
new
Query [ 256 ] ,
DBResult:Result
;
format ( Query , sizeof ( Query ) , "SELECT `Bani` , `Scor` , `Ucideri` , `Decese` FROM `Jucatori` WHERE `Nume` = '%s' AND `Parola` = '%s'"
, P_DATA [ playerid ] [ Nume ] , DB_Escape ( inputtext ) ) ;
Result = db_query ( Conturi , Query ) ;
if ( db_num_rows ( Result ) )
{
new
Field [ 30 ]
;
db_get_field_assoc ( Result , "Bani" , Field , 30 ) ;
P_DATA [ playerid ] [ Bani ] = strval ( Field ) ;
ResetPlayerMoney ( playerid ) ;
GivePlayerMoney ( playerid , strval ( Field ) ) ;
db_get_field_assoc ( Result , "Scor" , Field , 30 ) ;
P_DATA [ playerid ] [ Scor ] = strval ( Field ) ;
SetPlayerScore ( playerid , strval ( Field ) ) ;
db_get_field_assoc ( Result , "Ucideri" , Field , 30 ) ;
P_DATA [ playerid ] [ Ucideri ] = strval ( Field ) ;
db_get_field_assoc ( Result , "Decese" , Field , 30 ) ;
P_DATA [ playerid ] [ Decese ] = strval(Field);
Logat [ playerid ] = true ;
}
else
{
SPD ( playerid , DIALOG_LOGIN , DIALOG_STYLE_PASSWORD , "Logheaza-te" , "Parola gresita.Introdu parola in casuta de mai jos:" , "O.K" , "" ) ;
}
db_free_result ( Result ) ;
return ( 1 ) ;
}
return ( 0 ) ;
}
Cam asta a fost tot.Dar, ca sa nu primiti erori la compilare, adaugati stock-ul DB_Escape la final de script:
stock DB_Escape ( text [] )
{
new
ret[ MAX_INI_ENTRY_TEXT * 2 ] ,
ch ,
i ,
j
;
while ( ( ch = text [ i++ ] ) && j < sizeof ( ret ) )
{
if ( ch == '\'' )
{
if ( j < sizeof ( ret ) - 2 )
{
ret [ j++ ] = '\'' ;
ret [ j++ ] = '\'' ;
}
}
else if ( j < sizeof ( ret ) )
{
ret [ j++ ] = ch ;
}
else
{
j++ ;
}
}
ret [ sizeof ( ret ) - 1 ] = '\0' ;
return ret ;
}
Daca a-ti urmat toti pasii corect (de la cap la coada) ar trebuii sa functioneze corect sistemul de inregistrare/logare.O zi buna!
#include " a_samp "
#include " zcmd "
#include " YSI\y_ini "
Acum ca am facut asta, o sa va intrebati de ce am adaugat si y_ini.L-am adaugat fiindca fisierul y_ini contine stock-ul strcpy iar ca sa nu il mai adaug in acest tutorial, am inclus y_ini.Ca sa fie mai usor de explicat si pentru a nu irosi ceva linii, o sa definesc dialog-urile si functile pe care le voi folosi in acest tutorial:
#define SPD ShowPlayerDialog
#define SCM SendClientMessage
#define DIALOG_REGISTER ( 2012 )
#define DIALOG_LOGIN ( 2013 )
#define isnull(%1) ((!(%1[0])) || (((%1[0]) == '\1') && (!(%1[1]))))
Acum ca am facut si asta, trebuie sa facem si datele jucatorului (new-urile):
enum PlayerData
{
Nume [ MAX_PLAYER_NAME ] ,
Bani ,
Scor ,
Ucideri ,
Decese
} ;
new
P_DATA [ MAX_PLAYERS ] [ PlayerData ] ,
bool: Logat [ MAX_PLAYERS ] ,
DB:Conturi
;
Daca a-ti facut toate astea, putem trece la urmatorul pas, acesta fiind pasul care tine de baza de date:
public OnFilterScriptInit ( )
{
new
string [ 756 ]
;
Conturi = db_open ( "Conturi.db" ) ;
strcat ( string , "CREATE TABLE IF NOT EXISTS `Jucatori`" , 756 ) ;
strcat ( string , "(`ID` INTEGER PRIMARY KEY AUTOINCREMENT ,\
`Nume` TEXT ,\
`Parola` TEXT ,\
`Bani` NUMERIC ,\
`Scor` NUMERIC , " , 756 ) ;
strcat ( string , "`Ucideri` NUMERIC ,\
`Decese` NUMERIC ) " , 756 ) ;
db_free_result ( db_query ( Conturi , string ) ) ;
return ( 1 ) ;
}
Daca vreti sa faceti sistemul de inregistrare in modul de joc, schimbati OnFilterScriptInit cu OnGameModeInit.La acest "callback", se va crea baza de date/se va deschide baza de date.Pentru a functiona corect, la final cand modul de joc/scriptul se inchide, trebuie sa inchideti si baza de date:
public OnFilterScriptExit ( )
{
db_close ( Conturi ) ;
return ( 1 ) ;
}
Aici povestea se repeta.Schimbati OnFilterScriptExit cu OnGameModeExit daca aveti "gamemode" si nu "filterscript".Acum ca am facut si baza de date, trebuie sa facem ca atunci cand un jucator se conecteaza, sa ii apara dialogul de inregistrare/logare.Cum facem asta? Simplu.La "callback"-ul OnPlayerConnect trebuie sa verificam daca jucatorul exista in baza de date sau nu:
public OnPlayerConnect ( playerid )
{
new
Query [ 256 ] ,
pNume [ MAX_PLAYER_NAME ] ,
DBResult:Result
;
Logat [ playerid ] = false ;
GetPlayerName ( playerid , pNume , MAX_PLAYER_NAME ) ;
strcpy ( P_DATA [ playerid ] [ Nume ] , DB_Escape ( pNume ) , MAX_PLAYER_NAME ) ;
format ( Query , 256 , "SELECT * FROM `Jucatori` WHERE `Nume` = '%s'" , P_DATA [ playerid ] [ Nume ] ) ;
Result = db_query ( Conturi , Query ) ;
if ( db_num_rows ( Result ) > 0 )
SPD ( playerid , DIALOG_LOGIN , DIALOG_STYLE_PASSWORD , "Logheaza-te" , "Introdu parola in casuta de mai jos:" , "O.K" , "" ) ;
else
SPD ( playerid , DIALOG_REGISTER , DIALOG_STYLE_PASSWORD , "Inregistreaza-te" , "Introdu parola in casuta de mai jos:" , "O.K" , "" ) ;
db_free_result ( Result ) ;
return ( 1 ) ;
}
Acum ca am trecut si de acest pas cu succes, trebuie sa facem ca atunci cand jucatorul se deconecteaza, sa ii se salveze datele.Presupun ca va intrebati "CUM?!" deci am sa va arat cum se poate face asta.Prima data trebuie sa verificam daca jucatorul este logat (de asta se ocupa "bool: Logat"):
public OnPlayerDisconnect ( playerid , reason )
{
if ( Logat [ playerid ] )
{
new
Query [ 256 ]
;
format ( Query , sizeof ( Query ) , "UPDATE `Jucatori` SET `Bani` = '%d' ,`Scor` = '%d' , `Ucideri` = '%d' , `Decese` = '%d' WHERE `Nume` = '%s'"
, GetPlayerMoney ( playerid ) , GetPlayerScore ( playerid ) , P_DATA [ playerid ] [ Ucideri ] , P_DATA [ playerid ] [ Decese ] , P_DATA [ playerid ] [ Nume ] ) ;
db_free_result ( db_query ( Conturi , Query ) ) ;
}
return ( 1 ) ;
}
Acum se salveaza datele jucatorului.Trebuie sa mai facem si "Uciderile" si "Decesele" jucatorului.Pentru a realiza acest lucru, avem nevoie de public-ul (callback-ul) OnPlayerDeath:
public OnPlayerDeath ( playerid , killerid , reason )
{
P_DATA [ playerid ] [ Decese ] ++ ;
if ( killerid != INVALID_PLAYER_ID )
{
P_DATA [ killerid ] [ Ucideri ] ++ ;
}
return ( 1 ) ;
}
Dupa ce am facut si asta, cred ca trebuie sa facem si ultimul pas (pasul final), cel care consta il salvarea si generarea datelor jucatorului.Pentru a realiza asta, ne vom folosi de public-ul OnDialogResponse.Folosindune de acesta, vom mai verifica daca parola introdusa este corecta/gresita sau daca parola introdusa de jucator este "null" adica daca jucatorul nu a introdus nimic:
public OnDialogResponse ( playerid , dialogid , response , listitem , inputtext [ ] )
{
if ( dialogid == DIALOG_REGISTER )
{
if ( !response || isnull(inputtext ) ) return SPD ( playerid , DIALOG_REGISTER , DIALOG_STYLE_PASSWORD , "Inregistreaza-te" , "Introdu parola in casuta de mai jos:" , "O.K" , "" ) ;
new
Query [ 256 ]
;
format ( Query , sizeof ( Query ) , "INSERT INTO `Jucatori` ( `Nume` , `Parola` , `Bani` , `Scor` , `Ucideri` , `Decese` ) VALUES ( '%s' , '%s' , '%d' , '%d' , '%d' , '%d' )"
, P_DATA [ playerid ] [ Nume ] , DB_Escape ( inputtext ) , 0 , 0 , 0 , 0 ) ;
db_free_result ( db_query ( Conturi , Query ) ) ;
SCM ( playerid , -1 , "Te-ai inregistrat cu succes." ) ;
Logat [ playerid ] = true ;
return ( 1 ) ;
}
if ( dialogid == DIALOG_LOGIN )
{
if ( !response || isnull ( inputtext ) ) return SPD ( playerid , DIALOG_LOGIN , DIALOG_STYLE_PASSWORD , "Logheaza-te" , "Introdu parola in casuta de mai jos:" , "O.K" , "" ) ;
new
Query [ 256 ] ,
DBResult:Result
;
format ( Query , sizeof ( Query ) , "SELECT `Bani` , `Scor` , `Ucideri` , `Decese` FROM `Jucatori` WHERE `Nume` = '%s' AND `Parola` = '%s'"
, P_DATA [ playerid ] [ Nume ] , DB_Escape ( inputtext ) ) ;
Result = db_query ( Conturi , Query ) ;
if ( db_num_rows ( Result ) )
{
new
Field [ 30 ]
;
db_get_field_assoc ( Result , "Bani" , Field , 30 ) ;
P_DATA [ playerid ] [ Bani ] = strval ( Field ) ;
ResetPlayerMoney ( playerid ) ;
GivePlayerMoney ( playerid , strval ( Field ) ) ;
db_get_field_assoc ( Result , "Scor" , Field , 30 ) ;
P_DATA [ playerid ] [ Scor ] = strval ( Field ) ;
SetPlayerScore ( playerid , strval ( Field ) ) ;
db_get_field_assoc ( Result , "Ucideri" , Field , 30 ) ;
P_DATA [ playerid ] [ Ucideri ] = strval ( Field ) ;
db_get_field_assoc ( Result , "Decese" , Field , 30 ) ;
P_DATA [ playerid ] [ Decese ] = strval(Field);
Logat [ playerid ] = true ;
}
else
{
SPD ( playerid , DIALOG_LOGIN , DIALOG_STYLE_PASSWORD , "Logheaza-te" , "Parola gresita.Introdu parola in casuta de mai jos:" , "O.K" , "" ) ;
}
db_free_result ( Result ) ;
return ( 1 ) ;
}
return ( 0 ) ;
}
Cam asta a fost tot.Dar, ca sa nu primiti erori la compilare, adaugati stock-ul DB_Escape la final de script:
stock DB_Escape ( text [] )
{
new
ret[ MAX_INI_ENTRY_TEXT * 2 ] ,
ch ,
i ,
j
;
while ( ( ch = text [ i++ ] ) && j < sizeof ( ret ) )
{
if ( ch == '\'' )
{
if ( j < sizeof ( ret ) - 2 )
{
ret [ j++ ] = '\'' ;
ret [ j++ ] = '\'' ;
}
}
else if ( j < sizeof ( ret ) )
{
ret [ j++ ] = ch ;
}
else
{
j++ ;
}
}
ret [ sizeof ( ret ) - 1 ] = '\0' ;
return ret ;
}
Daca a-ti urmat toti pasii corect (de la cap la coada) ar trebuii sa functioneze corect sistemul de inregistrare/logare.O zi buna!