Page 1 of 1

[Tut] MySql - Save/Load/Usefull Things (Xp Mod)

Posted: Sat Oct 10, 2026 12:28 pm
by Archive-Poster
Hello there,

Ive decided to write this down as an addition to the other tutorial here :

But then I would be using MySql. I will try to keep it simple and focus more on the mysql part then on the xp mod itself.

Be aware, when reading this you should have basic knowledge about pawn coding, I will try to learn you something about mysql coding on this tutorial.

We will start with a main plugin :

Code: Select all

#include <amxmodx>

#define PLUGIN "Tutorial"
#define VERSION "1.0"
#define AUTHOR "Grim"

new iExp[33]

// Pcvar's
new cKill
new cHeadshot
new cDeath

public plugin_init() {
    register_plugin(PLUGIN, VERSION, AUTHOR)
    
    register_event("DeathMsg", "Event_DeathMsg", "a") // Register death event
    
    // register the Pcvar's
    cKill = register_cvar("exp_kill", "2")
    cHeadshot = register_cvar("exp_headshot", "4")
    cDeath = register_cvar("exp_death", "1")
}

public Event_DeathMsg()
{
    new iKiller = read_data(1) // read the data to get the killer and victim
    new iVictim = read_data(2)
    
    if(is_user_alive(iKiller)) // Check if the killer is alive in case he killed himself
    {
        if(read_data(3)) // Check if it was a headshot
        {
            iExp[iKiller] += get_pcvar_num(cHeadshot) // Add the amount of the Pcvar to iExp
        }
        else
        {
            iExp[iKiller] += get_pcvar_num(cKill)
        }
    }
    iExp[iVictim] -= get_pcvar_num(cDeath) // Decrease the amount of the Pcvar from iExp
} 


Then we start adding mysql to it.

First include sqlx

Code: Select all

#include <sqlx>
Then we start to create a mysql init

Code: Select all

public MySql_Init()
{
    // we tell the API that this is the information we want to connect to,
    // just not yet. basically it's like storing it in global variables
    g_SqlTuple = SQL_MakeDbTuple(Host,User,Pass,Db)
   
    // ok, we're ready to connect
    new ErrorCode,Handle:SqlConnection = SQL_Connect(g_SqlTuple,ErrorCode,g_Error,charsmax(g_Error))
    if(SqlConnection == Empty_Handle)
        // stop the plugin with an error message
        set_fail_state(g_Error)
       
    new Handle:Queries
    // we must now prepare some random queries
    Queries = SQL_PrepareQuery(SqlConnection,"CREATE TABLE IF NOT EXISTS tutorial (steamid varchar(32),exp INT(11))")

    if(!SQL_Execute(Queries))
    {
        // if there were any problems the plugin will set itself to bad load.
        SQL_QueryError(Queries,g_Error,charsmax(g_Error))
        set_fail_state(g_Error)
       
    }
    
    // Free the querie
    SQL_FreeHandle(Queries)
   
    // you free everything with SQL_FreeHandle
    SQL_FreeHandle(SqlConnection)   
} 
To prevent errors we free the handle at a mapend

Code: Select all

public plugin_end()
{
    // free the tuple - note that this does not close the connection,
    // since it wasn't connected in the first place
    SQL_FreeHandle(g_SqlTuple)
} 
Now we need to load and save the player hes stats

Code: Select all

public Load_MySql(id)
{
    new szSteamId[32], szTemp[512]
    get_user_authid(id, szSteamId, charsmax(szSteamId))
    
    new Data[1]
    Data[0] = id
    
    //we will now select from the table `tutorial` where the steamid match
    format(szTemp,charsmax(szTemp),"SELECT * FROM `tutorial` WHERE (`tutorial`.`steamid` = '%s')", szSteamId)
    SQL_ThreadQuery(g_SqlTuple,"register_client",szTemp,Data,1)
}

public register_client(FailState,Handle:Query,Error[],Errcode,Data[],DataSize)
{
    if(FailState == TQUERY_CONNECT_FAILED)
    {
        log_amx("Load - Could not connect to SQL database.  [%d] %s", Errcode, Error)
    }
    else if(FailState == TQUERY_QUERY_FAILED)
    {
        log_amx("Load Query failed. [%d] %s", Errcode, Error)
    }

    new id
    id = Data[0]
    
    if(SQL_NumResults(Query) < 1) 
    {
        //.if there are no results found
        
        new szSteamId[32]
        get_user_authid(id, szSteamId, charsmax(szSteamId)) // get user's steamid
        
        //  if its still pending we can't do anything with it
        if (equal(szSteamId,"ID_PENDING"))
            return PLUGIN_HANDLED
            
        new szTemp[512]
        
        // now we will insturt the values into our table.
        format(szTemp,charsmax(szTemp),"INSERT INTO `tutorial` ( `steamid` , `exp`)VALUES ('%s','0');",szSteamId)
        SQL_ThreadQuery(g_SqlTuple,"IgnoreHandle",szTemp)
    } 
    else 
    {
        // if there are results found
        iExp[id]         = SQL_ReadResult(Query, 1)
    }
    
    return PLUGIN_HANDLED
} 

Code: Select all

public Save_MySql(id)
{
    new szSteamId[32], szTemp[512]
    get_user_authid(id, szSteamId, charsmax(szSteamId))
    
    // Here we will update the user hes information in the database where the steamid matches.
    format(szTemp,charsmax(szTemp),"UPDATE `tutorial` SET `exp` = '%i' WHERE `tutorial`.`steamid` = '%s';",iExp[id], szSteamId)
    SQL_ThreadQuery(g_SqlTuple,"IgnoreHandle",szTemp)
} 
Now our final code will look like this :

Code: Select all

#include <amxmodx>
#include <sqlx>

#define PLUGIN "Tutorial"
#define VERSION "1.0"
#define AUTHOR "Grim"

// Ur Mysql Information
new Host[]     = "hostname"
new User[]    = "username"
new Pass[]     = "password"
new Db[]     = "database"


new Handle:g_SqlTuple
new g_Error[512]


new iExp[33]

// Pcvar's
new cKill
new cHeadshot
new cDeath

public plugin_init() {
    register_plugin(PLUGIN, VERSION, AUTHOR)
    
    register_event("DeathMsg", "Event_DeathMsg", "a") // Register death event
    
    // register the Pcvar's
    cKill = register_cvar("exp_kill", "2")
    cHeadshot = register_cvar("exp_headshot", "4")
    cDeath = register_cvar("exp_death", "1")
    
    set_task(1.0, "MySql_Init") // set a task to activate the mysql_init
}

public MySql_Init()
{
    // we tell the API that this is the information we want to connect to,
    // just not yet. basically it's like storing it in global variables
    g_SqlTuple = SQL_MakeDbTuple(Host,User,Pass,Db)
   
    // ok, we're ready to connect
    new ErrorCode,Handle:SqlConnection = SQL_Connect(g_SqlTuple,ErrorCode,g_Error,charsmax(g_Error))
    if(SqlConnection == Empty_Handle)
        // stop the plugin with an error message
        set_fail_state(g_Error)
       
    new Handle:Queries
    // we must now prepare some random queries
    Queries = SQL_PrepareQuery(SqlConnection,"CREATE TABLE IF NOT EXISTS tutorial (steamid varchar(32),exp INT(11))")

    if(!SQL_Execute(Queries))
    {
        // if there were any problems
        SQL_QueryError(Queries,g_Error,charsmax(g_Error))
        set_fail_state(g_Error)
       
    }
    
    // close the handle
    SQL_FreeHandle(Queries)
   
    // you free everything with SQL_FreeHandle
    SQL_FreeHandle(SqlConnection)   
}

public plugin_end()
{
    // free the tuple - note that this does not close the connection,
    // since it wasn't connected in the first place
    SQL_FreeHandle(g_SqlTuple)
}

public Load_MySql(id)
{
    new szSteamId[32], szTemp[512]
    get_user_authid(id, szSteamId, charsmax(szSteamId))
    
    new Data[1]
    Data[0] = id
    
    //we will now select from the table `tutorial` where the steamid match
    format(szTemp,charsmax(szTemp),"SELECT * FROM `tutorial` WHERE (`tutorial`.`steamid` = '%s')", szSteamId)
    SQL_ThreadQuery(g_SqlTuple,"register_client",szTemp,Data,1)
}

public register_client(FailState,Handle:Query,Error[],Errcode,Data[],DataSize)
{
    if(FailState == TQUERY_CONNECT_FAILED)
    {
        log_amx("Load - Could not connect to SQL database.  [%d] %s", Errcode, Error)
    }
    else if(FailState == TQUERY_QUERY_FAILED)
    {
        log_amx("Load Query failed. [%d] %s", Errcode, Error)
    }

    new id
    id = Data[0]
    
    if(SQL_NumResults(Query) < 1) 
    {
        //.if there are no results found
        
        new szSteamId[32]
        get_user_authid(id, szSteamId, charsmax(szSteamId)) // get user's steamid
        
        //  if its still pending we can't do anything with it
        if (equal(szSteamId,"ID_PENDING"))
            return PLUGIN_HANDLED
            
        new szTemp[512]
        
        // now we will insturt the values into our table.
        format(szTemp,charsmax(szTemp),"INSERT INTO `tutorial` ( `steamid` , `exp`)VALUES ('%s','0');",szSteamId)
        SQL_ThreadQuery(g_SqlTuple,"IgnoreHandle",szTemp)
    } 
    else 
    {
        // if there are results found
        iExp[id]         = SQL_ReadResult(Query, 1)
    }
    
    return PLUGIN_HANDLED
}

public Save_MySql(id)
{
    new szSteamId[32], szName[32], szTemp[512]
    get_user_authid(id, szSteamId, charsmax(szSteamId))
    
    // Here we will update the user hes information in the database where the steamid matches.
    format(szTemp,charsmax(szTemp),"UPDATE `tutorial` SET `exp` = '%i' WHERE `tutorial`.`steamid` = '%s';",iExp[id], szSteamId)
    SQL_ThreadQuery(g_SqlTuple,"IgnoreHandle",szTemp)
}

public IgnoreHandle(FailState,Handle:Query,Error[],Errcode,Data[],DataSize)
{
    SQL_FreeHandle(Query)
    
    return PLUGIN_HANDLED
}

public client_putinserver(id)
{
    Load_MySql(id)
}

public client_disconnect(id)
{
    Save_MySql(id)
}

public Event_DeathMsg()
{
    new iKiller = read_data(1) // read the data to get the killer and victim
    new iVictim = read_data(2)
    
    if(is_user_alive(iKiller)) // Check if the killer is alive in case he killed himself
    {
        if(read_data(3))
        {
            iExp[iKiller] += get_pcvar_num(cHeadshot) // Add the amount of the Pcvar to iExp
        }
        else
        {
            iExp[iKiller] += get_pcvar_num(cKill)
        }
    }
    iExp[iVictim] -= get_pcvar_num(cDeath) // Decrease the amount of the Pcvar from iExp
} 
Good to know

Get a ranking :

Code: Select all

public Show_Rank(id) // register cmd to this function
{
    for(new i; i < MaxPlayers; i++)
    {
        if(is_user_connected(i))
           Save_MySql(i) // Save all stats to get the correct rank
    }
        
    new Data[1]
    Data[0] = id
    
    new szTemp[512]
    format(szTemp,charsmax(szTemp),"SELECT COUNT(*) FROM `tutorial` WHERE `exp` >= %d", Exp[id])
    // Select the count where the exp is matching or higher (Incase of equal exp)
    SQL_ThreadQuery(g_SqlTuple,"Sql_Rank",szTemp,Data,1)
        
    return PLUGIN_CONTINUE
}

public Sql_Rank(FailState,Handle:Query,Error[],Errcode,Data[],DataSize)
{
    if(FailState == TQUERY_CONNECT_FAILED)
            log_amx("Load - Could not connect to SQL database.  [%d] %s", Errcode, Error)
    else if(FailState == TQUERY_QUERY_FAILED)
            log_amx("Load Query failed. [%d] %s", Errcode, Error)
  
    new count = 0
    count = SQL_ReadResult(Query,0)
    if(count == 0)
    count = 1
    
    new id
    id = Data[0]

    client_print(id, print_chat, "You're rank is %i with %i exp", count, Exp[id]);
    
    return PLUGIN_HANDLED
} 
How to store floats:

Code: Select all

//example
Queries[0] = SQL_PrepareQuery(SqlConnection, "CREATE TABLE IF NOT EXISTS %s (steamid varchar(32), yourfloat FLOAT(11,3))", szTableName);

// FLOAT(11,3)
// 11 = maximum number of digits
// 3 = maximum number of digits behind the decimal point

// Load data

new Float:yourfloat
SQL_ReadResult( Query, Column, yourfloat ); 
How to delete rows:

Code: Select all

new szTemp[256], Data[1];

Data[0] = id

format(szTemp,charsmax(szTemp),"DELETE FROM `%s` WHERE `steamid` = '%s'", szMainTable, szSteamid);
SQL_ThreadQuery(SqlTuple,"IgnoreHandle",szTemp,Data,1); 
ToDo List
- Adding more examples.

Common mistakes

- Ur mysql database does not support external connections.
- 1 of the 4 informations you fill in is not correct. (username, password, hostname, databasename)
- Ur created table differences from the updating you are doing the a record. look @ <to be added>