[Tutorial] [BUD]Blazing User Database | Complete documentation
#1

Blazing User Database | Complete tutorial
Written by Rock
Choose what you want to learn:
1. Creating database and columns
2. Save and extract data from the database
3. Set and extract data DIRECTLY into/from database
4. Last set of functions which BUD have.



You will learn how to use these functions:
Код:
        BUD::Setting( setting[], value )
bool    BUD::Initialize( )
bool    BUD::Exit( )
        BUD::VerifyColumn( column[], type[, default value ] )
bool    BUD::IsNameRegistered( name[] )
bool    BUD::RegisterName( name[], password[] )
        BUD::UnregisterName( name[] )
bool    BUD::CheckAuth( name[], password[] )
        BUD::GetNameUID( name[] )
Float   BUD::GetFloatEntry( uid, entry[] )
        BUD::GetIntEntry( uid, entry[] )
        BUD::GetStringEntry( uid, entry[], &value[][, size ] )
bool    BUD::MultiGet( uid, type definitions, ( entry, &variable )... )
bool    BUD::MultiSet( uid, type definitions, ( entry, value )... )
bool    BUD::SetIntEntry( uid, entry[], value )
bool    BUD::SetFloatEntry( uid, entry[], Float:value )
bool    BUD::SetStringEntry( uid, entry[], value[][, size ] )
        BUD::RunQuery( query[], bool:store_results )
        BUD::EscapeSqlString( string[ ] )
        BUD::GetSortedData( &results[][],  column )
bool    BUD::GetNamesForSortedData( results[][], num_results, &names[][] )
The beginning:

Before include BUD we need to have this defined
pawn Код:
#define BUD_USE_WHIRLPOOL false // false - if you don't want to use the WHIRLPOOL plugin and true if we use it
#define BUD_MAX_COLUMNS 10 // 10 - max number of columns witch will be alowed in the database
After we defined this we can include BUD
pawn Код:
#include < BUD >
Now that we included BUD we can begin to use it
Next, go to OnGameModeInit if it's a gamemode or OnfilterScriptInit if it's fs

pawn Код:
public OnFilterScriptInit( )
{

}
Between brackets add:
pawn Код:
BUD::Setting(  opt.Database, "Users.db"  ); // "Users.db" will be the name of the database we create
BUD::Setting(  opt.Asynchronous, true    ); // If it's true it will be faster but in case of anything happens with your computer the database can be corrupted.
BUD::Setting(  opt.KeepAliveTime, 3000   ); // The database will remain active vor 3000 milliseconds after it's used, this is useful for performance
BUD::Setting(  opt.CheckForUpdates, true ); // Name says it all, true if you want to search for updates
After all those setting in same callback we need to initialize the database
WARNING: This must be done before we will use any of it's functions
pawn Код:
BUD::Initialize( );
After we make the settings now we will create columns on the database
pawn Код:
BUD::VerifyColumn(  "Money", BUD::TYPE_NUMBER );
Money - Name of the column
BUD::TYPE:
TYPE_NUMBER: Numbers (1,2,3, 34343)
TYPE_STRING : String(bla, test, rock)
TYPE_FLOAT : Float(2.0, 3.2, 34.33)
TYPE_BINARY : Not supported yet, this will be in the next version

Optional parameters for VerifyColumn:
pawn Код:
BUD::VerifyColumn(  "Money", BUD::TYPE_NUMBER, 50 ); // 50 - optional parameter, this will add value 50 to column "Money" when it's created
Optional parameters can be used also for strings and floats the same way.
If it's a string do like this:
pawn Код:
BUD::VerifyColumn(  "Rank", BUD::TYPE_STRING, "Newbie"  );
After we are done with the settings and columns, go to OnFilterScriptExit or OnGameModeExit if it's a gamemode and add:
pawn Код:
BUD::Exit( );
ATTENTION: Use BUD::Exit( ) ONLY under OnGameModeExit or OnFilterScriptExit and no more elsewhere!

At the end your script will look like this:
pawn Код:
#include < a_samp >

#define BUD_USE_WHIRLPOOL false
#define BUD_MAX_COLUMNS 10

#include < BUD >

public OnFilterScriptInit( )
{
   BUD::Setting(  opt.Database, "Users.db"  );
   BUD::Setting(  opt.Asynchronous, true    );
   BUD::Setting(  opt.KeepAliveTime, 3000   );
   BUD::Setting(  opt.CheckForUpdates, true );

   BUD::Initialize( );
   BUD::VerifyColumn(  "Points", BUD::TYPE_NUMBER  );

   // With optional parameter
   BUD::VerifyColumn(  "Money",  BUD::TYPE_NUMBER, 50  );
   BUD::VerifyColumn(  "Rank",   BUD::TYPE_STRING, "Newbie"  );
   BUD::VerifyColumn(  "Health", BUD::TYPE_FLOAT, 100.00  );
}

public OnFilterScriptExit( )
{
   BUD::Exit( );
}
Read below for the next parts.
Reply
#2

Part 2:

In this part we will learn how to:
- Verify if the player have an account on the server and if not, create one
- How to save score, money, rank, level and others

First we will beggin with player account.
Before we start you will need this stock inside your scrip:
pawn Код:
stock GetName( playerid )
{
        new _RocKzSk[ MAX_PLAYER_NAME ];
        GetPlayerName( playerid, _RocKzSk, sizeof _RocKzSk );
        return ( _RocKzSk );
}
If it is already in your script it's even better.

Now, we go to OnPlayerConnect and add this inside the brackets.
pawn Код:
if( !BUD::IsNameRegistered( GetName( playerid ) ) )
{
       // Register code, dialogs, client messages, ..., ...
}
This function will verify if the new connected player has an account on your server and if not you can show a dialog for register and send a message to let him know.
(You will see an example at the end of the post)

Ok, now under !BUD::IsNameRegistered add this:
pawn Код:
else
{
       // login code
}
This is the opposite of function used above. (see that "else") which means if player has an account.
This is an example how it should look like right now:
pawn Код:
new _rK[ 128 ];
if( !BUD::IsNameRegistered( GetName( playerid ) ) )
{
   format( _rK, sizeof( _rK ), "Welcome %s\nYou need an account to play on this server.", GetName( playerid ) );
    ShowPlayerDialog( playerid, Register_D1, DIALOG_STYLE_MSGBOX, "New Account", _rK, "Register", "Kick" );
}
else
{
   format( _rK, sizeof( _rK ), "Welcome %s\nThis account is already registered.\nLogin now.", GetName( playerid ) );
   ShowPlayerDialog( playerid, Login_D1, DIALOG_STYLE_MSGBOX, "Login", _rK, "Login", "Kick" );
}
IMPORTANT!
When you do the register code, you need to use this function, otherways account will not be registered.
pawn Код:
if ( BUD::RegisterName( GetName( playerid ), inputtext ) )
{
       // Code..code..code
}
Inside brackets of BUD::RegisterName add:
pawn Код:
new
   iUID = BUD::GetNameUID( GetName( playerid ) )
;
BUD::GetNameUID will get player unique ID which will be stored also in the database.(It's like playerid)
Under GetNameUID add:
pawn Код:
BUD::MultiSet( iUID, "s", "Password", inputtext );
Which will save the password inside the database.
ATTENTION: Use BUD::MultiSet ONLY in this function and to save player stats and no more elsewhere.

Ok, now that you've learned how to verify if a player has an account or not let's beggin with saving stats.
To beggin go to OnPlayerDisconnect and add again GetNameUID to get player unique id from the database.
pawn Код:
new
   iUID = BUD::GetNameUID( GetName( playerid ) )
;
(In the database unique id's are saved beggining with 1, 2, 3.., .., 101..)

Under that add:
pawn Код:
BUD::MultiSet( iUID, "iisi",
   "Money", GetPlayerMoney( playerid ),
   "Score", GetPlayerScore( playerid ),
   "Rank", ROCK_PDATA[ playerid ][ rK_Rank ],
   "Level", ROCK_PDATA[ playerid][ rK_Level]
);
This will save data on the column you created in the first part of this tutorial.
If you know how sscanf works you will know that "i" means integrer, "s" string, "f" float and I used "iis" because the first two things to save are integrers(Money and Score), the third one is a string and las is an integrer again.

ATTENTION: Name you used in MultiSet needs to be exactly the same name as your columns in your database.
In my case Money, Score, Rank and Level.

Wonder how to extract and set dates when player connects and login?
Go to OnDialogResponse and inside the login dialog add:
pawn Код:
if( BUD::CheckAuth( GetName( playerid ), inputtext )
{

}
inputtext - Text which player will type in login dialog(DIALOG_STYLE_INPUT), in our case, password.
So this means it will compare the password from the database with password you or other player typed.

Now in the brackets of CheckAuth add:
pawn Код:
new
   _Money, _Score, _Rank, _Level,
   iUID = BUD::GetNameUID( GetName( playerid ) )
;
Unique ID again and variables to store data from database.
Under that add:
pawn Код:
BUD::MultiGet( iUID, "iis[20]i",
   "Money", _Money,
   "Score", _Score,
   "Rank" , _Rank,
   "Level", _Level
);
MultiGet will extract data from the database and store into variables you created above.
I think you see above that I used lenght [20] in "s". In MultiGet it's needed to set string lenght.(like sscanf)

Now to set value to variables you use in your script under MultiGet simply add:
pawn Код:
GivePlayerMoney( playerid, _Score );
SetPlayerScore( playerid, _Money );
ROCK_PDATA[ playerid ][ rK_Rank ] = _Rank;
ROCK_PDATA[ playerid ][ rK_Level ] = _Level;
Or other variables you use, this is just an example.

Now if you follow all the steps from the beginning you are ready to create your own register/login system!

Here is an example of how it should look like
REMEMBER! It's just an example, you will get errors if you try to compile it.
Reply
#3

Good Tutorial
Reply
#4

Good work Rock, its useful for beginners
Reply
#5

Part 3:
In this part we will learn how to extract anytime, anywhere data from the columns and set them when we want and where we want.

I will beggin with strings:
GetStringEntry - Get a string from the database
pawn Код:
BUD::GetStringEntry( uid, entry[ ], &value[ ][, size ] )
Will do the work for us.
Parameters:
uid - Unique ID of player
entry[ ] - Name of the column from where we want to extract string
value[ ][, size ] - String to store extracted data

Use:
pawn Код:
new
   rTest[ 30 ],
   iUID = BUD::GetNameUID( GetName( playerid ) )
;
BUD::GetStringEntry( iUID, "Rank", rTest );
printf( "%s", rTest );
-----------------------------------------------------------------------------------
SetStringEntry - Set string directly into the database
pawn Код:
BUD::SetStringEntry( uid, entry[ ], value[ ][, size ] )
Parameters are exactly the same as GetStringEntry.

Use:
pawn Код:
BUD::SetStringEntry( iUID, "Rank", "Newbie" ); // "Newbie" - string which will be stored in the column "Rank"
-----------------------------------------------------------------------------------

GetIntEntry - Extract integrer value
pawn Код:
BUD::GetIntEntry( uid, entry[ ] )
It's easier than string, simply do:
pawn Код:
new
   rTest[ 20 ],
   iUID = BUD::GetNameUID( GetName( playerid ) )
;
format( rTest, 20, "Val: %i", BUD::GetIntEntry( iUID, "Money" ) );
printf( "%i", rTest );
-----------------------------------------------------------------------------------
SetIntEntry - Set integrer value
pawn Код:
BUD::SetIntEntry( uid, entry[ ], value )
Use:
pawn Код:
BUD::SetIntEntry( iUID, "Money", 50 ); // 50 - value we will add
-----------------------------------------------------------------------------------

GetFloatEntry - Extract floats
pawn Код:
BUD::GetFloatEntry( uid, entry[ ] )
Simple and useful:
pawn Код:
new
   rTest[ 50 ],
   iUID = BUD::GetNameUID( GetName( playerid ) )
;
format( rTest, 50, "Val: %f", BUD::GetFloatEntry( iUID, "Health" );
printf( "%f", rTest );
-----------------------------------------------------------------------------------

SetFloatEntry - Set float value
pawn Код:
BUD::SetFloatEntry( uid, entry[ ], Float:value )
Same as integrer:
pawn Код:
BUD::SetFloatEntry( iUID, "Health", 100.00 ) // 100.00 - value which will be set to column "Health"
Done.
ATTENTION: All values set with SetStringEntry, SetIntEntry and SetFloatEntry will replace old values in the database.
Reply
#6

Cool!
Reply
#7

Part 4:
This part will contain the last functions of BUD which you will see below.

BUD::RunQuery - Run a Query by yourself.
Код:
BUD::RunQuery( query[ ], bool:store_results )
Parameters:
query[ ] - Name of the Query you want to send to the database.
bool: store_results - Store the results?

Example use(count registered users):
pawn Код:
new
    iCount,
    szBuffer[ 32 ],
    DBResult: iResult = BUD::RunQuery( "SELECT COUNT(*) FROM `users`", true );

if ( iResult )
{
    db_get_field( iResult, 0, szBuffer, 31 );
    iCount = strval( szBuffer );
}
ATTENTION: There is no need for db_free_result after using BUD::RunQuery, BUD will take care of that for you.
-----------------------------------------------------------------------------------

BUD::EscapeSqlString - Used to prevent sql injections.
To protect your query from SQL injections simply run BUD::EscapeSqlString with the string you will insert as an argument.
If you're doing this for something enclosed in ` quotes:
pawn Код:
BUD::EscapeSqlString( string, '`' );
-----------------------------------------------------------------------------------

BUD::GetSortedData - Get the data sorted from a specified column.
pawn Код:
BUD::GetSortedData( &results[ ][ ],  column )
Parameters:
results[ ][ ][ ] - Results, you need to define them(see below)
column - Sort the results from what column?

BUD::GetNamesForSortedData - Get names for sorted data.
pawn Код:
BUD::GetNamesForSortedData( results[ ][ ], num_results, names[ ][ ] )
Parameters:
results[ ][ ][ ] - The string where sorted that was stored
num_results - Variable in which GetSortedData stored the results.
names[ ][ ] - A new variable to store the extracted names.

Example use for both:
pawn Код:
new
    BUD::Results: iMaxResults< 10 >, // Here we define results, < 10 > means how many variables will be sorted
    szaNames[ 10 ][ MAX_PLAYER_NAME +1 ], // Name for GetNamesForSortedData, see below
    iResults = BUD::GetSortedData( iMaxResults, "kills" ); // Store the sorted results into a variable

BUD::GetNamesForSortedData( iMaxResults, iResults, szaNames ); // Get names for all sorted data

if( iResults == BUD::INVALID_RESULTS ) // If sort failed.
    printf( "BUD::GetSortedData failed." );
else
{
    for ( new i = 0; i < iResults; i++ ) // Loop through results
    {
        printf( "User: %s (%d)\t%d", szaNames[ i ], brTest[ i ][ 0 ], brTest[ i ][ 1 ] );
    }
}
-----------------------------------------------------------------------------------

BUD::SetPassword - Change password for account
pawn Код:
BUD::SetPassword( uid, const password[ ] )
Parameters:
uid - Unique id of player
password - New password(It will be automatically hashed)

Example:
pawn Код:
new
   iUID = BUD::GetNameUID( GetName( playerid ) );
BUD::SetPassword( iUID, "test123" )
WARNING: Before you use this function add this somewhere in bud.inc

pawn Код:
global bool:BUD::SetPassword(uid, const password[]) {
    if (uid == BUD::INVALID_UID || !BUD::GetDB()) {
        return false;
    }

    new query[256];

    #if (BUD::USE_WHIRLPOOL)
        BUD::WhirlpoolHash(query, _, password);

        format(query, sizeof(query), "UPDATE `users` SET `passhash` = x'%s' WHERE `uid` = %d", query, uid);
    #else
        new passhash[65];
        BUD::JSCHash(password, passhash);

        format(query, sizeof(query), "UPDATE `users` SET `passhash` = '%s' WHERE `uid` = %d", passhash, uid);
    #endif

    new DBResult:dbrResult = db_query(g_dbKeptAlive, query);

    if (dbrResult) {
        db_free_result(dbrResult);

        return true;
    }

    return false;
}
Reply
#8

btw, nice give me example how to edit an offline acc?
for example /unban?
Reply
#9

Quote:
Originally Posted by ToiletDuck
Посмотреть сообщение
btw, nice give me example how to edit an offline acc?
for example /unban?
This should work, I guess.
pawn Код:
CMD:unban( playerid, params[ ] )
{
    new
        uUser;
       
    if( !IsPlayerAdmin( playerid ) ) return SendClientMessage( playerid, -1, "You need to be RCON Admin to use this command." );
    if( sscanf( params, "u", uUser ) ) return SendClientMessage( playerid, -1, "Syntax: /unban <player_name>" );
   
    new
        iUID = BUD::GetNameUID( GetName( uUser ) );
       
    if( BUD::GetIntEntry( iUID, "Banned" ) == 0 ) return SendClientMessage( playerid, -1, "Player not banned" );
    {
        BUD::SetIntEntry( iUID, "Banned", 0 );
        SendClientMessage( playerid, -1, "Player unbaned" );
    }
    return 1;
}
In your database banned users should have value 1 and 0 if not banned.
Reply
#10

Added SetPassword function, see THIS.
If I missed something just reply or pm me.
Reply
#11

hi.i learn the tutorial but when i suicide,fire and get explode.the wasted text show and wasted text not delete when the player spawn
Reply


Forum Jump:


Users browsing this thread: 3 Guest(s)