View Full Version : [Tut] MySql - Save/Load/Usefull Things (Xp Mod)
Hello there,
Ive decided to write this down as an addition to the other tutorial here :
http://forums.alliedmods.net/showthread.php?t=66497
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 :
#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
#include <sqlx>
Then we start to create a mysql init
// Credits to hawk552 from hes old tutorial
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,char smax(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_Err or))
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
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
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], 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 :
#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,char smax(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_Err or))
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
}
Credits to hawk552 from hes old tutorial -
http://forums.alliedmods.net/showthread.php?t=46779&highlight=mysql
Good to know
Get a ranking :
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:
//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:
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 @ https://forums.alliedmods.net/showthread.php?t=133063 )
Any suggestions to add? Have u seen mistakes?
Please report them.
Greetings Grim
alan_el_more
07-17-2010, 20:58
Good Job :D
lucas_7_94
07-17-2010, 21:29
Great work
PD: try to add when the server shutting down ( like plugin_end() or FM_GameShutdown , etc)
Alucard^
07-17-2010, 21:42
Really good job, at the moment i don't need to use mysql but i will need this in the future, thanks.
GJ man
It is Really Necessary
thx!
Thanks for the positive comments, I will add some usefull things later.
Kreation
07-18-2010, 18:01
Thanks for this, I might be able to use this in the future. Good job. :D
shuttle_wave
07-21-2010, 05:43
Wow. Nice TUT grim. would be cool as if u had a tutorial on how to extract those data from mysql and show it on the site :D. Good Job A++++
I think ErrorCode can be non-zero even when FailState is not TQUERY_QUERY_FAILED.
lucas_7_94
07-21-2010, 12:02
i have one cuestion , its not the same this
if(SQL_NumResults(Query) < 1) that this
if(!SQL_NumResults(Query)) ?
i have one cuestion , its not the same this
if(SQL_NumResults(Query) < 1) that this
if(!SQL_NumResults(Query)) ?
Pure theoreticly, the first is "if lower then 1" the other is "if equals 0". When there are bugs, strange things can occur and the first is the safest.
I think ErrorCode can be non-zero even when FailState is not TQUERY_QUERY_FAILED.
if the query did'nt failed and the connection also did'nt failed, the connection should be succesfull?
edit: sorry forgot about my other post.
if the query did'nt failed and the connection also did'nt failed, the connection should be succesfull?
edit: sorry forgot about my other post.
It appears that the error code can only be non-zero when the fail state is TQUERY_QUERY_FAILED. See here:
73 bool MysqlQuery::ExecuteR(QueryInfo *info, char *error, size_t maxlength)
74 {
75 int err;
76
77 if ( (err=mysql_real_query(m_pDatabase->m_pMysql, m_QueryString, (unsigned long)m_QueryLen)) )
78 {
79 info->errorcode = mysql_errno(m_pDatabase->m_pMysql);
80 info->success = false;
81 info->affected_rows = 0;
82 info->rs = NULL;
83 if (error && maxlength)
84 {
85 snprintf(error, maxlength, "%s", mysql_error(m_pDatabase->m_pMysql));
86 }
87 }
88 else
89 {
90 MYSQL_RES *res = mysql_store_result(m_pDatabase->m_pMysql);
91 if (!res)
92 {
93 if (mysql_field_count(m_pDatabase->m_pMysql) > 0)
94 {
95 //error !111!!11
96 info->errorcode = mysql_errno(m_pDatabase->m_pMysql);
97 info->success = false;
98 info->affected_rows = 0;
99 info->rs = NULL;
100 } else {
101 info->errorcode = 0;
102 info->success = true;
103 info->affected_rows = mysql_affected_rows(m_pDatabase->m_pMysql);
104 info->rs = NULL;
105 }
106 } else {
107 info->errorcode = 0;
108 info->success = true;
109 info->affected_rows = mysql_affected_rows(m_pDatabase->m_pMysql);
110 MysqlResultSet *rs = new MysqlResultSet(res, m_pDatabase->m_pMysql);
111 info->rs = rs;
112 }
113 }
114
115 return info->success;
116 }
That means you can ignore my comment.
shuttle_wave
07-22-2010, 00:22
Queries = SQL_PrepareQuery(SqlConnection,"CREATE TABLE IF NOT EXISTS tutorial (steamid varchar(32),exp INT(11))")
i dont get that bit. (steamid varchar(32),exp INT(11)) thats the bit i dont get. someone please explain
As siple as it is. At the mapstart we run that query, its going to look if the table already exists in the database. if not it will create a table with 2 fields, steamid and exp. varchar(32) is the same as "new String[32]" and I guess you know what an int is.
NzGamers
07-22-2010, 05:22
Nice Tutorial man. I see u explaining to Shuttle_Wave but im not very advance so wats exp INT(11)
exp is a field. When u save a record (a players steam id) you can set hes field. 1 field is hes steamid, the other is the amount of exp, we call the field exp and the player hes exp will be stored in there. an INT is just simply a number and the 11 is how many numbers it can contain. for example the max is 99.999.999.999
shuttle_wave
07-22-2010, 08:07
As siple as it is. At the mapstart we run that query, its going to look if the table already exists in the database. if not it will create a table with 2 fields, steamid and exp. varchar(32) is the same as "new String[32]" and I guess you know what an int is.
yeap. i get it now. ty vm
Nice Tutorial Grim, good Job :)
benjibau
07-23-2010, 14:34
an error with the rank i think because it's always first in rank:cry::cry:
but nice tutorial
an error with the rank i think because it's always first in rank:cry::cry:
but nice tutorial
Show ur code. Ask other players to say rank, might be because of equal scores. Its running flawless on my servers.
you should check if the victim is not the killer, because the killer's XP would increase if it's suicided
No, I check if the killer is still alive.
Alucard^
08-05-2010, 18:26
But grimvh2, isn't better if you use Killer != Victim instead of checking if user is alive using a native? i know is not a big deal but well...
Thanks grimvh2, very good tutorial and usefull.
But grimvh2, isn't better if you use Killer != Victim instead of checking if user is alive using a native? i know is not a big deal but well...
I think in some cases where the player kills him self, the killer and victim doesnt always return the same, I'm not sure but I guess in some cases with func_doors, trigger_hurt, drown, ... Anyway its not such big deal.
why should i use my sql instead of nvault, is it better?
Alucard^
08-20-2010, 11:41
why should i use my sql instead of nvault, is it better?
As far as i know is more faster than nvault and others files systems... and also you can combine mysql with others systems like with forum or others.
The only thing nvault could be usefull for is a few data to save. nVault is slower and when u get to much data in, ur server will lag. Mysql doesnt cause lag ( when its done good ). Can handle much more data and can be used for websites ( online top 15 or w/e ).
The MySQL data storing and retrieving functions are much more powerful than those of nVault. For basic data storing this does not make that much of a difference, though. That's why MySQL tutorials are sometimes problematic. MySQL is so powerful that you can not cover all of it. If someone plans to use MySQL he will often have to find more sources and really learn the syntax of MySQL queries. Imho it would be much more helpful to provide a set of stocks that would make MySQL as easy to use as nVault.
A huge difference is that a real MySQL database (not SQLite) is entirely seperate from the server itself. Handling huge data structures can cause problems with nVault while MySQL, especially when you use threaded querying, will not use any resources of the server.
Another nice thing is, that you can often make your plugin compatible with MySQL and SQLite at the same time. That way the user can use an external database, necessary for integration into actual websites, but also fall back to local server-storage if no MySQL database is at hand.
Suggestions for the tutorial:
- I believe that the tuple variable is not updated by SQL_Connect so you don't need to check it everytime but should after the SQL_MakeDbTuple call instead.
- You can remove most SQL_Connect calls anyway. This is not necessary for threaded querying.
- In the save function you don't use the name of the user. You should remove the variable and the get_user_name call.
- However, if you plan to use the name, you should cover string escaping aswell.
- Use formatex where applicable (read: everywhere in this tutorial).
- Think about statics and a global query buffer.
- Any reason to delay MySQL_Init for that long?
That's all I can see right now.
The MySQL data storing and retrieving functions are much more powerful than those of nVault. For basic data storing this does not make that much of a difference, though. That's why MySQL tutorials are sometimes problematic. MySQL is so powerful that you can not cover all of it. If someone plans to use MySQL he will often have to find more sources and really learn the syntax of MySQL queries. Imho it would be much more helpful to provide a set of stocks that would make MySQL as easy to use as nVault.
A huge difference is that a real MySQL database (not SQLite) is entirely seperate from the server itself. Handling huge data structures can cause problems with nVault while MySQL, especially when you use threaded querying, will not use any resources of the server.
Another nice thing is, that you can often make your plugin compatible with MySQL and SQLite at the same time. That way the user can use an external database, necessary for integration into actual websites, but also fall back to local server-storage if no MySQL database is at hand.
Suggestions for the tutorial:
- I believe that the tuple variable is not updated by SQL_Connect so you don't need to check it everytime but should after the SQL_MakeDbTuple call instead.
- You can remove most SQL_Connect calls anyway. This is not necessary for threaded querying.
- In the save function you don't use the name of the user. You should remove the variable and the get_user_name call.
- However, if you plan to use the name, you should cover string escaping aswell.
- Use formatex where applicable (read: everywhere in this tutorial).
- Think about statics and a global query buffer.
- Any reason to delay MySQL_Init for that long?
That's all I can see right now.
Thx for the advice.
What do you mean with a global query buffer?
Just like you use a global variable to store errors you can use a global variable to store the queries you are formatting. There's no reason to create a new 512 variable everytime you need to make a query.
GuessWhat
10-31-2010, 01:41
how do i get an sql server? what is hostname, pass ,db ? cause i got a plugin fail to load
How can I get the XP of a player and add a prefix before the player's name based on the XP? (prefix in chat messages)
Exolent[jNr]
10-31-2010, 12:59
how do i get an sql server? what is hostname, pass ,db ? cause i got a plugin fail to load
You have to get one with web hosting. Find a website that has free SQL databases or rent web hosting that has one.
GuessWhat
11-02-2010, 01:43
how i can update many field at the same time?
i have a database which contain steamid, goals, exp, points, exp, level, rank and so on. how can i update them all at once?
new goals[33]
new iExp[33]
new points[33]
new level[33]
new rank[33]
...
...
...
format(szTemp,charsmax(szTemp),"UPDATE `tutorial` SET `exp` = '%i' WHERE `tutorial`.`steamid` = '%s';",iExp[id], szSteamId)
format(szTemp,charsmax(szTemp),"UPDATE `tutorial` SET `exp` = '%i', `otherthing` = '%i', `astring` = '%s' WHERE `tutorial`.`steamid` = '%s';",iExp[id], otherthing[id], string[id] szSteamId)
Get it?
format(szTemp,charsmax(szTemp),"UPDATE `tutorial` SET `exp` = '%i', `otherthing` = '%i', `astring` = '%s' WHERE `tutorial`.`steamid` = '%s';",iExp[id], otherthing[id], string[id] szSteamId)
Get it?
can you add a top15 for the Tut.
benjibau
11-03-2010, 07:23
can you add a top15 for the Tut.
Nice idea
Exolent[jNr]
11-03-2010, 13:35
can you add a top15 for the Tut.
It's only a simple query. The rest is things you should know from the tutorial (or another SQL tutorial) which is reading the 15 top players.
SELECT steamid, exp FROM tutorial ORDER BY exp DESC LIMIT 15;
SELECT steamid, exp - Gets the steamid and exp from the table for each player
FROM tutorial - Gets data from tutorial table
ORDER BY exp DESC - Orders by the row's "exp" value descending so that the highest exp is first
LIMIT 15 - Limit 15 players in the results so if there are more than 15 they aren't used.
After executing this query, you would just need a simple loop:
new szSteamID[ 35 ], iExp;
new iPos = 1;
while( SQL_MoreResults( hQuery ) )
{
// SELECT steamid, exp
// steamid is first, so its column number is 0
// then exp, so its column number is 1
SQL_ReadResult( hQuery, 0, szSteamID, charsmax( szSteamID ) );
iExp = SQL_ReadResult( hQuery, 1 );
// print the player's top15 position and data
server_print( "#%i: %s - %i", iPos, szSteamID, iExp );
// increase to next top15 position and go to next row
iPos++;
SQL_NextRow( hQuery );
}
benjibau
11-03-2010, 14:37
Exolent i think if more good with board. I think is that ?
public ShowTop15(id)
{
new szSteamID[ 35 ], iExp;
new iPos = 1;
new MenuBody[512], len;
len = format(MenuBody, 511, "\yStats TOP 15^n";)
Place++
SQL_ReadResult(Query,1,Name,32)
Points = SQL_ReadResult(Query,2)
format(szTemp,charsmax(szTemp),"SELECT steamid, exp FROM tutorial ORDER BY exp DESC LIMIT 15;")
while( SQL_MoreResults( hQuery ) )
{
// SELECT steamid, exp
// steamid is first, so its column number is 0
// then exp, so its column number is 1
SQL_ReadResult( hQuery, 0, szSteamID, charsmax( szSteamID ) );
iExp = SQL_ReadResult(hQuery, 1);
// print the player's top15 position and data
len += format(MenuBody[len], 511-len, "^n\r%d. %s %d Points", iPos, szSteamID, iExp)
// increase to next top15 position and go to next row
iPos++;
SQL_NextRow( hQuery );
}
} can you correct if is wrong please ?
Exolent[jNr]
11-03-2010, 15:17
Try testing before you post. That code won't even compile.
benjibau
11-04-2010, 15:01
Oh i think using SQL_ThreadQuery() in a func called with register_clcmd
and in the func i added this for choose steamid, exp from tutorial and after
new Temp[512]
format(Temp,charsmax(Temp),"SELECT steamid, exp FROM tutorial ORDER BY exp DESC LIMIT 15;")
SQL_ThreadQuery(g_SqlTuple,"myfunc",Temp,Data,1)for exemple:
public ShowTop15(id)
{
//i must save stat for will haven't error into top15.
//
new Data[1]
Data[0] = id
new Temp[512]
format(Temp,charsmax(Temp),"SELECT steamid, exp FROM tutorial ORDER BY exp DESC LIMIT 15;")
SQL_ThreadQuery(g_SqlTuple,"Sql_Top15",Temp,Data,1)
return PLUGIN_CONTINUE;
}
public Sql_Top15(FailState,Handle:hQuery,Error[],Errcode,Data[],DataSize)
{
new szSteamID[ 35 ], iExp;
new iPos = 1;
while( SQL_MoreResults( hQuery ) )
{
SQL_ReadResult( hQuery, 0, szSteamID, charsmax( szSteamID ) );
iExp = SQL_ReadResult(hQuery, 1);
server_print( "#%i: %s - %i", iPos, szSteamID, iExp );
iPos++;
SQL_NextRow( hQuery );
}
}edit: i tested with this but not work.
Exolent[jNr]
11-04-2010, 18:45
public ShowTop15(id)
{
//i must save stat for will haven't error into top15.
//
new Data[1]
Data[0] = id
// no need for a variable since it's not being formatted
/*new Temp[512]
format(Temp,charsmax(Temp),"SELECT steamid, exp FROM tutorial ORDER BY exp DESC LIMIT 15;")
SQL_ThreadQuery(g_SqlTuple,"Sql_Top15",Temp,Data,1)*/
SQL_ThreadQuery(g_SqlTuple,"Sql_Top15","SELECT steamid, exp FROM tutorial ORDER BY exp DESC LIMIT 15;",Data,1)
return PLUGIN_CONTINUE;
}
public Sql_Top15(FailState,Handle:hQuery,Error[],Errcode,Data[],DataSize)
{
// get player who is looking at top
new id = Data[ 0 ];
// check for errors
if( FailState == TQUERY_CONNECT_FAILED
|| FailState == TQUERY_QUERY_FAILED )
{
log_amx( "Error on top15 query (%i): %s", Errcode, Error );
console_print( id, "Error on top15 query (%i): %s", Errcode, Error );
return;
}
new szSteamID[ 35 ], iExp;
new iPos = 1;
while( SQL_MoreResults( hQuery ) )
{
SQL_ReadResult( hQuery, 0, szSteamID, charsmax( szSteamID ) );
iExp = SQL_ReadResult( hQuery, 1 );
// print to player, not server
//server_print( "#%i: %s - %i", iPos, szSteamID, iExp );
console_print( id, "#%i: %s - %i", iPos, szSteamID, iExp );
iPos++;
SQL_NextRow( hQuery );
}
}
;1342133']public ShowTop15(id)
{
//i must save stat for will haven't error into top15.
//
new Data[1]
Data[0] = id
// no need for a variable since it's not being formatted
/*new Temp[512]
format(Temp,charsmax(Temp),"SELECT steamid, exp FROM tutorial ORDER BY exp DESC LIMIT 15;")
SQL_ThreadQuery(g_SqlTuple,"Sql_Top15",Temp,Data,1)*/
SQL_ThreadQuery(g_SqlTuple,"Sql_Top15","SELECT steamid, exp FROM tutorial ORDER BY exp DESC LIMIT 15;",Data,1)
return PLUGIN_CONTINUE;
}
public Sql_Top15(FailState,Handle:hQuery,Error[],Errcode,Data[],DataSize)
{
// get player who is looking at top
new id = Data[ 0 ];
// check for errors
if( FailState == TQUERY_CONNECT_FAILED
|| FailState == TQUERY_QUERY_FAILED )
{
log_amx( "Error on top15 query (%i): %s", Errcode, Error );
console_print( id, "Error on top15 query (%i): %s", Errcode, Error );
return;
}
new szSteamID[ 35 ], iExp;
new iPos = 1;
while( SQL_MoreResults( hQuery ) )
{
SQL_ReadResult( hQuery, 0, szSteamID, charsmax( szSteamID ) );
iExp = SQL_ReadResult( hQuery, 1 );
// print to player, not server
//server_print( "#%i: %s - %i", iPos, szSteamID, iExp );
console_print( id, "#%i: %s - %i", iPos, szSteamID, iExp );
iPos++;
SQL_NextRow( hQuery );
}
}
Thanks you,Exolent !
Exolent[jNr]
11-05-2010, 16:35
@grimvh
Your tutorial has errors that is spreading to users who copy/paste this for their own SQL saving.
Now our final code will look like this :
#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,char smax(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_Err or))
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 ErrorCode,Handle:SqlConnection = SQL_Connect(g_SqlTuple,ErrorCode,g_Error,char smax(g_Error))
if(g_SqlTuple == Empty_Handle)
set_fail_state(g_Error)
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)
SQL_FreeHandle(SqlConnection)
}
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
}
The problem is here:
public Load_MySql(id)
{
new ErrorCode,Handle:SqlConnection = SQL_Connect(g_SqlTuple,ErrorCode,g_Error,char smax(g_Error))
if(g_SqlTuple == Empty_Handle)
set_fail_state(g_Error)
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)
SQL_FreeHandle(SqlConnection)
}
SQL_Connect() is for direct queries using SQL_PrepareQuery() and SQL_ThreadQuery() does not require a connection because it is set to a thread and connect/execute when it can.
It should be:
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)
}
;1341153']It's only a simple query. The rest is things you should know from the tutorial (or another SQL tutorial) which is reading the 15 top players.
SELECT steamid, exp FROM tutorial ORDER BY exp DESC LIMIT 15;
SELECT steamid, exp - Gets the steamid and exp from the table for each player
FROM tutorial - Gets data from tutorial table
ORDER BY exp DESC - Orders by the row's "exp" value descending so that the highest exp is first
LIMIT 15 - Limit 15 players in the results so if there are more than 15 they aren't used.
After executing this query, you would just need a simple loop:
Code:
new szSteamID[ 35 ], iExp;
new iPos = 1;
while( SQL_MoreResults( hQuery ) ) { // SELECT steamid, exp // steamid is first, so its column number is 0 // then exp, so its column number is 1 SQL_ReadResult( hQuery, 0, szSteamID, charsmax( szSteamID ) );
iExp = SQL_ReadResult( hQuery, 1 );
// print the player's top15 position and data server_print( "#%i: %s - %i", iPos, szSteamID, iExp );
// increase to next top15 position and go to next row iPos++; SQL_NextRow( hQuery );
}
Question about this: How can I select the exp where player name = current player name?
Exolent[jNr]
11-07-2010, 11:42
Question about this: How can I select the exp where player name = current player name?
Read the tutorial where it loads the player's xp.
@exo: yes thanks, I already knew that but it seems that I forgot to modify a part. Someone already pointed out that mistake before. Thanks for telling something slipped me.
Question about this: How can I select the exp where player name = current player name?
You need the steam id of the player if you want to get anything of that player.
how to use set names 'utf8' ??
I have two errors with my plugin
L 11/26/2010 - 23:28:39: [MySQL] Invalid handle: 2
L 11/26/2010 - 23:28:39: [AMXX] Displaying debug trace (plugin "tbdm_xpmod.amxx")
L 11/26/2010 - 23:28:39: [AMXX] Run time error 10: native error (native "SQL_FreeHandle")
L 11/26/2010 - 23:28:39: [AMXX] [0] tbdm_xpmod.sma::plugin_end (line 94)
L 11/26/2010 - 23:29:05: Start of error session.
L 11/26/2010 - 23:29:05: Info (map "de_aztec_suncsm") (file "addons/amxmodx/logs/error_20101126.log")
L 11/26/2010 - 23:29:05: [MySQL] Invalid query handle: 1
L 11/26/2010 - 23:29:05: [AMXX] Displaying debug trace (plugin "tbdm_xpmod.amxx")
L 11/26/2010 - 23:29:05: [AMXX] Run time error 10: native error (native "SQL_ReadResult")
L 11/26/2010 - 23:29:05: [AMXX] [0] tbdm_xpmod.sma::Sql_Rank (line 235)
At line 94 I have
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)
}
And at line 235 I have
new icount = 0
icount=SQL_ReadResult(g_SqlTuple,0)
if(icount == 0)
icount = 1
Exolent[jNr]
11-27-2010, 04:00
You don't read a result from the tuple handle. You read it from the query handle.
And what do I have to modify?
http://www.amxmodx.org/funcwiki.php?go=func&id=1105
I got it
icount=SQL_ReadResult(Query,0)
Exolent[jNr]
11-27-2010, 15:07
SQL_ReadResult( Query, COLUMN, VARIABLE, MAXLEN [only if variable is a string] )
Terrible description.
You even linked to the funcwiki and put a worse description.
SQL_ReadResult ( Handle:query, column, {Float,_}:... )
Passing no extra params - return int
Passing one extra param - return float in 1st extra arg
Passing two extra params - return string in 1st arg, max length in 2nd
Example:
new num = SQL_ReadResult(query, 0)
new Float:num2
new str[32]
SQL_ReadResult(query, 1, num2)
SQL_ReadResult(query, 2, str, 31)
Pass 2 params for an integer to be returned.
new value = SQL_ReadResult( query, column );
Pass 3 params for a float value to be passed byref.
new Float:value;
SQL_ReadResult( query, column, value );
Pass 4 params for a string value to be passed byref.
new value[32];
SQL_ReadResult( query, column, value, charsmax( value ) );
This error always showing on console:
L 12/11/2010 - 10:43:27: [MySQL] Invalid handle: 0
L 12/11/2010 - 10:43:27: [AMXX] Displaying debug trace (plugin "mysql.amxx")
L 12/11/2010 - 10:43:27: [AMXX] Run time error 10: native error (native "SQL_FreeHandle")
L 12/11/2010 - 10:43:27: [AMXX] [0] mysql.sma::plugin_end (line 52)
Using original code.
Exolent[jNr]
12-11-2010, 17:31
Make sure that the handle is valid when created.
#include <amxmodx>
#include <sqlx>
#define PLUGIN "Tutorial"
#define VERSION "1.0"
#define AUTHOR "Grim"
new Host[] = "localhost"
new User[] = "root"
new Pass[] = "password"
new Db[] = "database"
new Handle:g_SqlTuple
new g_Error[512]
new iExp[33]
new cKill
new cHeadshot
new cDeath
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
register_event("DeathMsg", "Event_DeathMsg", "a")
cKill = register_cvar("exp_kill", "2")
cHeadshot = register_cvar("exp_headshot", "4")
cDeath = register_cvar("exp_death", "1")
set_task(1.0, "MySql_Init")
}
public MySql_Init()
{
g_SqlTuple = SQL_MakeDbTuple(Host,User,Pass,Db)
new ErrorCode,Handle:SqlConnection = SQL_Connect(g_SqlTuple,ErrorCode,g_Error,char smax(g_Error))
if(SqlConnection == Empty_Handle)
set_fail_state(g_Error)
new Handle:Queries
Queries = SQL_PrepareQuery(SqlConnection,"CREATE TABLE IF NOT EXISTS tutorial (steamid varchar(32),exp INT(11))")
if(!SQL_Execute(Queries))
{
SQL_QueryError(Queries,g_Error,charsmax(g_Err or))
set_fail_state(g_Error)
}
SQL_FreeHandle(Queries)
SQL_FreeHandle(SqlConnection)
}
public plugin_end()
{
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
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)
{
new szSteamId[32]
get_user_authid(id, szSteamId, charsmax(szSteamId))
if (equal(szSteamId,"ID_PENDING"))
return PLUGIN_HANDLED
new szTemp[512]
format(szTemp,charsmax(szTemp),"INSERT INTO `tutorial` ( `steamid` , `exp`)VALUES ('%s','0');",szSteamId)
SQL_ThreadQuery(g_SqlTuple,"IgnoreHandle",szTemp)
}
else
{
iExp[id] = SQL_ReadResult(Query, 1)
}
return PLUGIN_HANDLED
}
public Save_MySql(id)
{
new szSteamId[32], szTemp[512]
get_user_authid(id, szSteamId, charsmax(szSteamId))
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
}
1. I changed mysql connect info (host,db,user adn pass).
2. I put this code in blabla.sma file.
3. Compiling in amxx :)
4. put in server plugins folder, change plugins.cfg file (added: blabla.amxx)
but script doesn't work. mh don't create in mysql tutorial table..
connect work fine. maybe i just have wrong amxmodx version?
Excellent, I understood it very good. :D I will use it in a future because I am doing and improving my Mod, Great Thanks!
No one?
This happends when your table does'nt exists.
#include <amxmodx>
#include <sqlx>
#define PLUGIN "Tutorial"
#define VERSION "1.0"
#define AUTHOR "Grim"
new Host[] = "localhost"
new User[] = "root"
new Pass[] = "password"
new Db[] = "database"
new Handle:g_SqlTuple
new g_Error[512]
new iExp[33]
new cKill
new cHeadshot
new cDeath
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
register_event("DeathMsg", "Event_DeathMsg", "a")
cKill = register_cvar("exp_kill", "2")
cHeadshot = register_cvar("exp_headshot", "4")
cDeath = register_cvar("exp_death", "1")
set_task(1.0, "MySql_Init")
}
public MySql_Init()
{
g_SqlTuple = SQL_MakeDbTuple(Host,User,Pass,Db)
new ErrorCode,Handle:SqlConnection = SQL_Connect(g_SqlTuple,ErrorCode,g_Error,char smax(g_Error))
if(SqlConnection == Empty_Handle)
set_fail_state(g_Error)
new Handle:Queries
Queries = SQL_PrepareQuery(SqlConnection,"CREATE TABLE IF NOT EXISTS tutorial (steamid varchar(32),exp INT(11))")
if(!SQL_Execute(Queries))
{
SQL_QueryError(Queries,g_Error,charsmax(g_Err or))
set_fail_state(g_Error)
}
SQL_FreeHandle(Queries)
SQL_FreeHandle(SqlConnection)
}
public plugin_end()
{
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
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)
{
new szSteamId[32]
get_user_authid(id, szSteamId, charsmax(szSteamId))
if (equal(szSteamId,"ID_PENDING"))
return PLUGIN_HANDLED
new szTemp[512]
format(szTemp,charsmax(szTemp),"INSERT INTO `tutorial` ( `steamid` , `exp`)VALUES ('%s','0');",szSteamId)
SQL_ThreadQuery(g_SqlTuple,"IgnoreHandle",szTemp)
}
else
{
iExp[id] = SQL_ReadResult(Query, 1)
}
return PLUGIN_HANDLED
}
public Save_MySql(id)
{
new szSteamId[32], szTemp[512]
get_user_authid(id, szSteamId, charsmax(szSteamId))
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
} 1. I changed mysql connect info (host,db,user adn pass).
2. I put this code in blabla.sma file.
3. Compiling in amxx :)
4. put in server plugins folder, change plugins.cfg file (added: blabla.amxx)
but script doesn't work. mh don't create in mysql tutorial table..
connect work fine. maybe i just have wrong amxmodx version?
Error Log?
Could be wrong modules enabled or the connection from your server to your mysql db
(srr for double post)
Added new examples :
-How to store floats.
-How to delete a row.
If you want more examples about things you want to see in this tutorial, feel free to pm me or to post something here.
[AMXX] Run time error 10: native error (native "SQL_ThreadQuery")
I get this message in my console when I try to ask for my rank and how much points I have.
Same with:
Load_MySql (line 94)
SQL_ThreadQuery(g_SqlTuple,"register_client",szTemp,Data,1)
and
Save_MySql (line 144)
SQL_ThreadQuery(g_SqlTuple,"IgnoreHandle",szTemp)
Why it doesn't work? I use local Database.
Error is always:
Invalid info tuple handle: 0
There is no correct connection to your database? Are you're tables created? I dont think so.
I tried to connect with a External Database Checker, it says it works.
And no there isn't any table.
ddo amx_modules to see if all ur modules are running correctly
EpicMonkey
06-05-2012, 04:07
whats with the szname
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)
}
your not using it...
This is supposed to be to save playername in-game. But he doesn't used it :]
EpicMonkey
06-12-2012, 02:12
This is supposed to be to save playername in-game. But he doesn't used it :]
thats exactly what am pointing out :3
V I R U S
09-18-2012, 20:12
Thanks for the great tut, but there is still a leak in whole AMXX SQL system.
For a day, i've noticed my website fallig down with an error "TOO MANY CONNECTIONS". No problem to raise up the number of connections for MySQL server, but i've noticed that every one CStrike + AMXX gameservers, makes over 8 SQL connections.
Somehow, that suxx. Mby there is some way to create only one connection to database and use that one for every plugin?
Thanks for the great tut, but there is still a leak in whole AMXX SQL system.
For a day, i've noticed my website fallig down with an error "TOO MANY CONNECTIONS". No problem to raise up the number of connections for MySQL server, but i've noticed that every one CStrike + AMXX gameservers, makes over 8 SQL connections.
Somehow, that suxx. Mby there is some way to create only one connection to database and use that one for every plugin?
The only thing that i can think now, it's to register a native and call it every time when you want to insert/retrieve some data into/from a DB. If a connection it's already active, wait to finish then close it and reopen a new one.
4444leozinho
09-24-2012, 16:00
I was wondering how do to put a function for admin to load the information from the steam that he enter.
aron9forever
09-11-2014, 07:35
The only thing that i can think now, it's to register a native and call it every time when you want to insert/retrieve some data into/from a DB. If a connection it's already active, wait to finish then close it and reopen a new one.
I also had this problem and I found out it's a problem in the tutorial:
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 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)
}
SQL_FreeHandle(Query)
return PLUGIN_HANDLED
}
Notice the extra SQL_FreeHandle(Query) before returning PLUGIN_HANDLED
new connections are created for every user that logs in and is already registered because the original "loading" query never actually calls "IgnoreHandle"
This tutorial have so much bugs, I dont know why any people didnt noticed before. With this way to save in mysql, I guarantee you that you ll have a lot of lost data.
This tutorial have so much bugs, I dont know why any people didnt noticed before. With this way to save in mysql, I guarantee you that you ll have a lot of lost data.
Make a new tutorial :up:
Make a new tutorial :up:
I'm exploring the sqlx module, I'm not a expert on it, but when I finish the way I'm saving I'll make a tutorial about it
This tutorial just gave me cancer when he loads the player data in client_putinserver...
This tutorial just gave me cancer when he loads the player data in client_putinserver...
Idk anything about mysql, but i don't see why is that a problem.
It should be on client authorized to be safer, and he inserts into the table the players stats if they are new right on it, and it should be when the players make some xp
It should be on client authorized to be more saffer, and he inserts into the table the players stats if they are new right on it, and it should be when the players make some xp
To be honest authorized doesn't means more safe since authorized is when the player is valid (example, steam server kicking a non-steam user). Putinserver is called after authorized so i think there is nothing wrong with it (connect->authorized->putinserver).
About saving xp, i dont see why that is wrong.
guipatinador
12-22-2014, 11:54
Normally the order is,
client_connect -> client_authorized -> client_putinserver
But in some (rare) situations client_authorized is called after,
client_connect -> client_putinserver -> client_authorized
Note that there is no default order and client_connect is always the first.
============
Keep in mind that client_authorized sometimes is called to fast, right after plugin_init. This could be dangerous if you create the global mysql handle in plugin_init or plugin_cfg.
g_SqlTuple = SQL_MakeDbTuple( szHost, szUser, szPass, szDB )
Thats why some coders use client_putinserver.
To be honest authorized doesn't means more safe since authorized is when the player is valid (example, steam server kicking a non-steam user). Putinserver is called after authorized so i think there is nothing wrong with it (connect->authorized->putinserver).
About saving xp, i dont see why that is wrong.
I cant be specific in english but I guarantee you that if the player stats were only saved when they make some xo or another thing that you're trying to save is more safe too.
Keep in mind that client_authorized sometimes is called to fast, right after plugin_init. This could be dangerous if you create the global mysql handle in plugin_init or plugin_cfg.
g_SqlTuple = SQL_MakeDbTuple( szHost, szUser, szPass, szDB )
Thats why some coders use client_putinserver.
I saw in your plugin that you set a task after client authorized, thats the reason why you do that?
guipatinador
12-22-2014, 16:59
I saw in your plugin that you set a task after client authorized, thats the reason why you do that?
Yes.
Normally the order is,
client_connect -> client_authorized -> client_putinserver
But in some (rare) situations client_authorized is called after,
client_connect -> client_putinserver -> client_authorized
Note that there is no default order and client_connect is always the first.
============
Keep in mind that client_authorized sometimes is called to fast, right after plugin_init. This could be dangerous if you create the global mysql handle in plugin_init or plugin_cfg.
g_SqlTuple = SQL_MakeDbTuple( szHost, szUser, szPass, szDB )
Thats why some coders use client_putinserver.
1- Does this mean if we use client_putinserver it wouldn't be necessary to use a task after client authorized like you do?
2- Where else can we create the global handle that would remove the risk of client_authorized being called too fast causing problems?
3- Is a task of 4.0 seconds in client_authorized really needed? or would something like 0.1 work just as good?
guipatinador
12-23-2014, 06:06
1- Does this mean if we use client_putinserver it wouldn't be necessary to use a task after client authorized like you do?
client_putinserver is always a risk to get the player authid. Use client_authorized for safety.
2- Where else can we create the global handle that would remove the risk of client_authorized being called too fast causing problems?You can't. Use plugin_init or plugin_cfg.
3- Is a task of 4.0 seconds in client_authorized really needed? or would something like 0.1 work just as good?It is required. I'm not sure the ammount of time. For example amxbans uses 2 seconds,
public client_authorized(id) {
//fix for the invalid tuple error at mapchange, only a fast fix now
if(g_SqlX==Empty_Handle) {
set_task(2.0,"client_authorized",id)
return PLUGIN_HANDLED
}
// code...
}
public client_authorized(id) {
//fix for the invalid tuple error at mapchange, only a fast fix now
if(g_SqlX==Empty_Handle) {
set_task(2.0,"client_authorized",id)
return PLUGIN_HANDLED
}
// code...
}
Checking the empty handle is definitly better than create unnecessary tasks. Now the server is happy and the data will be secure :3
guipatinador
12-23-2014, 06:38
Its not "definitly better".
If the plugin cannot connect to database (example: database offline, wrong password, etc), client_authorized is called each 2 seconds because g_SqlX will be always Empty_Handle.
Its not "definitly better".
If the plugin cannot connect to database (example: database offline, wrong password, etc), client_authorized is called each 2 seconds because g_SqlX will be always Empty_Handle.
That's because you are noob :3
Set task time for 5.0 to another function that isn't client_authorized. Didn't even noticed you looped the client authorized lol, thats so wrong :grrr:
guipatinador
12-23-2014, 07:49
Didn't even noticed you looped the client authorized lol, thats so wrong :grrr:
Thats an example of amx bans, https://code.google.com/p/plukom-amxx-plugins/source/browse/trunk/scripting/amxbans_main.sma?r=3&spec=svn17#239
Obviously looping client_authorized isn't a good idea.
This should be ok:
#define TASK_SQL 432531
#define MAX_PLAYERS 32
new g_Steam[MAX_PLAYERS + 1][35]
public client_authorized(Id)
{
get_user_authid(Id, g_Steam[Id], charsmax(g_Steam)) // Lets get SteamID just once. Safe for client_disconnect saving
if(g_SqlX == Empty_Handle)
set_task(5.0,"LoadShit",Id + TASK_SQL)
else
LoadShit(Id + TASK_SQL)
}
public LoadShit(Id)
{
Id-= TASK_SQL
// Code
}
guipatinador
12-23-2014, 18:53
Its okay.
But I would do the following only to prevent offline databases,
public LoadShit(Id)
{
if(g_SqlX == Empty_Handle)
{
// something is wrong with the connection (maybe offline / wrong ip / user / password)
return
}
Id-= TASK_SQL
// Code
}
=========================
charsmax(g_Steam))
If g_Steam it's a bidimensional array it shoud be,
charsmax(g_Steam[]))
Its okay.
But I would do the following only to prevent offline databases,
public LoadShit(Id)
{
if(g_SqlX == Empty_Handle)
{
// something is wrong with the connection (maybe offline / wrong ip / user / password)
return
}
Id-= TASK_SQL
// Code
}
Or just using a variable and put it positive in plugin_init after know if we got an Empty_Handle and work with the variable. Anyway, that's something i don't need right now. I am very new into sql so i have some doubts.
Should i regist like this:
SQL_ThreadQuery(g_Ranking, "EmptyFunction", "CREATE TABLE IF NOT EXISTS Rankings (Steam TEXT, Level NUMERIC, Kills NUMERIC, Deaths NUMERIC);")
Or should i create one table for each thing?
The reason why i am asking this is because i am currently using this to get data:
formatex(Query, charsmax(Query), "SELECT Kills FROM Rankings WHERE Steam = '%s';", g_Steam[Id])
SQL_ThreadQuery(g_Ranking, "Query_Handler", Query, Data, charsmax(Data))
And in Query_Handler: SQL_ReadResult(pQuery, 0)
With this could i get all the data and parse it or something? Or will i have to do 3 queries?
And last question. Should i update things everytime the values change or loop a task to save it from x in x time?
guipatinador
12-23-2014, 20:47
Should i regist like this:
SQL_ThreadQuery(g_Ranking, "EmptyFunction", "CREATE TABLE IF NOT EXISTS Rankings (Steam TEXT, Level NUMERIC, Kills NUMERIC, Deaths NUMERIC);")
Or should i create one table for each thing?
Your "CREATE TABLE..." query is ok but personally I would change two things.
1 - Replace TEXT by VARCHAR.
"CREATE TABLE IF NOT EXISTS Rankings (Steam VARCHAR(35), Level INT, Kills INT, Deaths INT)"
2 - Use a non-threaded query for "CREATE TABLE...", since its called in plugin_init / plugin_cfg once and will not affect the gameplay (for the rest, use always threaded querys).
new Handle:Queries = SQL_PrepareQuery(g_Ranking, "CREATE TABLE IF NOT EXISTS Rankings (Steam VARCHAR(35), Level INT, Kills INT, Deaths INT)")
if(!SQL_Execute( Queries ))
{
// optionally you can turn off the plugin
SQL_QueryError(Queries, g_Error, charsmax(g_Error))
set_fail_state(g_Error)
}
SQL_FreeHandle(Queries)
The reason why i am asking this is because i am currently using this to get data:
formatex(Query, charsmax(Query), "SELECT Kills FROM Rankings WHERE Steam = '%s';", g_Steam[Id])
SQL_ThreadQuery(g_Ranking, "Query_Handler", Query, Data, charsmax(Data))
And in Query_Handler: SQL_ReadResult(pQuery, 0)
With this could i get all the data and parse it or something? Or will i have to do 3 queries?Its simple with a single query. Just change "SELECT Kills" to "SELECT *" to select all the fields.
Optionally you can select the fields you want,
formatex(Query, charsmax(Query), "SELECT Level, Kills Deaths FROM Rankings WHERE Steam = '%s';", g_Steam[Id])
SQL_ThreadQuery(g_Ranking, "Query_Handler", Query, Data, charsmax(Data))
And then in Query_Handler,
iLevel = SQL_ReadResult(pQuery, 0) // first field
iKills = SQL_ReadResult(pQuery, 1) // second field
iDeaths = SQL_ReadResult(pQuery, 2) // third field
And last question. Should i update things everytime the values change or loop a task to save it from x in x time?Updating values every time they change may generate a lot of traffic between the server and the database. In most situations the most recommendable is saving at client_disconnect.
Unfortunately when the map change client_disconnect is called for everyone so it may cause a lot of traffic too.
Can anyone make me an example plugin for rank using MySQL. Save Rank, kills, deaths. When player say /rank then show message: "Your rank is %d with %d kills and %d deaths". THXX
Grim, In this tutorial, you should save the steam ID when a player join the server and save it as a global variable, because it isn't safe to detected the steam id of someone when they disconnect (as you do on this tutorial)
Bro, I want to know how to save rank position, kills, deaths using mysql to name, not steam id. thxx
I didn't answer to your request frosty, but btw, why don't you use steam id for saving instead of the name?
I didn't answer to your request frosty, but btw, why don't you use steam id for saving instead of the name?
Guess why. Everyone that requests to save by name instead of steam id, requests it for only one single reason: They want to be banned :crab:
nvm... I just want to save using MySQL. Can anyone make me an example plugin plzz ???
froogy, you have an example of a plugin that saves data in this thread
So, can anyone edit BaD CopY's plugin and change nVault to MySQL ?
#include <amxmodx>
#include <amxmisc>
#include <colorchat>
#include <csstats>
#include <nvault>
#include <csx>
#define PLUGIN "Rank System"
#define VERSION "1.0"
#define AUTHOR "BaD CopY"
new gTime[33]
new gVault
public plugin_init() {
register_plugin(PLUGIN, VERSION, AUTHOR)
register_clcmd("say /rank", "cmd_rank")
register_clcmd("say rank", "cmd_rank")
register_clcmd("team_say /rank", "cmd_rank")
register_clcmd("team_say rank", "cmd_rank")
gVault = nvault_open("TIME")
}
public cmd_rank(id)
{
new stats[8], body[8], szName[33];
get_user_name(id, szName, 32)
new rank_pos = get_user_stats(id, stats, body)
new rank_max = get_statsnum()
new iTimeMins = gTime[id] / 60
static Deaths = 0, Kills = 0, Float:Ratio = 0.0
Deaths = stats[1], Kills = stats[0], Ratio = Deaths == 0 ? (float(Kills)) : (float(Kills) / float(Deaths))
ColorChat(0, GREEN, "^4[Rank]^3 %s^1's rank is ^4%d^1 of ^4%d ^3-- ^1KpD: ^4%.2f^1 [Online: %i m]", szName, rank_pos, rank_max, Ratio, iTimeMins)
return PLUGIN_CONTINUE;
}
public client_authorized(id)
{
loaddata(id)
}
public client_disconnect(id)
{
gTime[id] += get_user_time(id)
savedata(id)
}
stock savedata(id)
{
new AuthId[65]
get_user_authid(id, AuthId, charsmax(AuthId))
new VaultKey[64], VaultData[256]
format(VaultKey, 63, "%s-TIME", AuthId)
format(VaultData, 254, "%i", gTime[id])
nvault_set(gVault, VaultKey, VaultData)
return PLUGIN_CONTINUE
}
stock loaddata(id)
{
new AuthID[35]
get_user_authid(id,AuthID,charsmax(AuthID ))
new vaultkey[64],vaultdata[256]
format(vaultkey,63,"%s-TIME" ,AuthID)
format(vaultdata,255,"%i",gTime[id])
nvault_get(gVault,vaultkey,vaultdata,charsmax (vaultdata))
new Time[33]
parse(vaultdata, Time, charsmax(Time))
gTime[id] = str_to_num(Time)
}
So, can anyone edit BaD CopY's plugin and change nVault to MySQL ?
#include <amxmodx>
#include <amxmisc>
#include <colorchat>
#include <csstats>
#include <nvault>
#include <csx>
#define PLUGIN "Rank System"
#define VERSION "1.0"
#define AUTHOR "BaD CopY"
new gTime[33]
new gVault
public plugin_init() {
register_plugin(PLUGIN, VERSION, AUTHOR)
register_clcmd("say /rank", "cmd_rank")
register_clcmd("say rank", "cmd_rank")
register_clcmd("team_say /rank", "cmd_rank")
register_clcmd("team_say rank", "cmd_rank")
gVault = nvault_open("TIME")
}
public cmd_rank(id)
{
new stats[8], body[8], szName[33];
get_user_name(id, szName, 32)
new rank_pos = get_user_stats(id, stats, body)
new rank_max = get_statsnum()
new iTimeMins = gTime[id] / 60
static Deaths = 0, Kills = 0, Float:Ratio = 0.0
Deaths = stats[1], Kills = stats[0], Ratio = Deaths == 0 ? (float(Kills)) : (float(Kills) / float(Deaths))
ColorChat(0, GREEN, "^4[Rank]^3 %s^1's rank is ^4%d^1 of ^4%d ^3-- ^1KpD: ^4%.2f^1 [Online: %i m]", szName, rank_pos, rank_max, Ratio, iTimeMins)
return PLUGIN_CONTINUE;
}
public client_authorized(id)
{
loaddata(id)
}
public client_disconnect(id)
{
gTime[id] += get_user_time(id)
savedata(id)
}
stock savedata(id)
{
new AuthId[65]
get_user_authid(id, AuthId, charsmax(AuthId))
new VaultKey[64], VaultData[256]
format(VaultKey, 63, "%s-TIME", AuthId)
format(VaultData, 254, "%i", gTime[id])
nvault_set(gVault, VaultKey, VaultData)
return PLUGIN_CONTINUE
}
stock loaddata(id)
{
new AuthID[35]
get_user_authid(id,AuthID,charsmax(AuthID ))
new vaultkey[64],vaultdata[256]
format(vaultkey,63,"%s-TIME" ,AuthID)
format(vaultdata,255,"%i",gTime[id])
nvault_get(gVault,vaultkey,vaultdata,charsmax (vaultdata))
new Time[33]
parse(vaultdata, Time, charsmax(Time))
gTime[id] = str_to_num(Time)
}
try
#include <amxmodx>
#include <amxmisc>
#include <colorchat>
#include <csstats>
#include <csx>
#include <sqlx>
#define PLUGIN "Rank System"
#define VERSION "1.0"
#define AUTHOR "BaD CopY"
// Ur Mysql Information
new Host[] = "hostname"
new User[] = "username"
new Pass[] = "password"
new Db[] = "database"
new gTime[33]
new Handle:g_SqlTuple
new g_Error[512]
public plugin_init() {
register_plugin(PLUGIN, VERSION, AUTHOR)
register_clcmd("say /rank", "cmd_rank")
register_clcmd("say rank", "cmd_rank")
register_clcmd("team_say /rank", "cmd_rank")
register_clcmd("team_say rank", "cmd_rank")
}
public MySql_Init()
{
g_SqlTuple = SQL_MakeDbTuple(Host,User,Pass,Db)
new ErrorCode,Handle:SqlConnection = SQL_Connect(g_SqlTuple,ErrorCode,g_Error,char smax(g_Error))
if(SqlConnection == Empty_Handle)
set_fail_state(g_Error)
new Handle:Queries
Queries = SQL_PrepareQuery(SqlConnection,"CREATE TABLE IF NOT EXISTS tutorial (steamid varchar(32),time INT(11))")
if(!SQL_Execute(Queries))
{
SQL_QueryError(Queries,g_Error,charsmax(g_Err or))
set_fail_state(g_Error)
}
SQL_FreeHandle(Queries)
SQL_FreeHandle(SqlConnection)
}
public cmd_rank(id)
{
new stats[8], body[8], szName[33];
get_user_name(id, szName, 32)
new rank_pos = get_user_stats(id, stats, body)
new rank_max = get_statsnum()
new iTimeMins = gTime[id] / 60
static Deaths = 0, Kills = 0, Float:Ratio = 0.0
Deaths = stats[1], Kills = stats[0], Ratio = Deaths == 0 ? (float(Kills)) : (float(Kills) / float(Deaths))
ColorChat(0, GREEN, "^4[Rank]^3 %s^1's rank is ^4%d^1 of ^4%d ^3-- ^1KpD: ^4%.2f^1 [Online: %i m]", szName, rank_pos, rank_max, Ratio, iTimeMins)
return PLUGIN_CONTINUE;
}
public client_authorized(id)
{
Load_MySql(id)
}
public client_disconnect(id)
{
gTime[id] += get_user_time(id)
Save_MySql(id)
}
public Load_MySql(id)
{
new szSteamId[32], szTemp[512]
get_user_authid(id, szSteamId, charsmax(szSteamId))
new Data[1]
Data[0] = id
format(szTemp,charsmax(szTemp),"SELECT * FROM `tutorial` WHERE (`tutorial`.`steamid` = '%s')", szSteamId)
SQL_ThreadQuery(g_SqlTuple,"register_client",szTemp,Data,1)
}
public Save_MySql(id)
{
new szSteamId[32], szTemp[512]
get_user_authid(id, szSteamId, charsmax(szSteamId))
format(szTemp,charsmax(szTemp),"UPDATE `tutorial` SET `time` = '%i' WHERE `tutorial`.`steamid` = '%s';",gTime[id], szSteamId)
SQL_ThreadQuery(g_SqlTuple,"IgnoreHandle",szTemp)
}
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)
{
new szSteamId[32]
get_user_authid(id, szSteamId, charsmax(szSteamId))
if (equal(szSteamId,"ID_PENDING"))
return PLUGIN_HANDLED
new szTemp[512]
format(szTemp,charsmax(szTemp),"INSERT INTO `tutorial` ( `steamid` , `timef`)VALUES ('%s','0');",szSteamId)
SQL_ThreadQuery(g_SqlTuple,"IgnoreHandle",szTemp)
}
else
{
gTime[id] = SQL_ReadResult(Query, 1)
}
return PLUGIN_HANDLED
}
public plugin_end()
{
SQL_FreeHandle(g_SqlTuple)
}
Can you fix the code and make to show hours and minuts online, not just minutes ? :D
And can you say me for what we need this part of the code:
new Host[] = "hostname"
new User[] = "username"
new Pass[] = "password"
new Db[] = "database"
thxx for replay bro :)
Can you fix the code and make to show hours and minuts online, not just minutes ? :D
And can you say me for what we need this part of the code:
new Host[] = "hostname"
new User[] = "username"
new Pass[] = "password"
new Db[] = "database"
thxx for replay bro :)
Are you sure that you want a sql and not nvault/fvault plugin?
Anyway, i need help about two thing. How do i get a string?
Also, lets say that i have in db the same steam id 2 times, but different values. How do i get those variables?
Because MySQL is most popular vault system and I want to learn how to use it :)
Because MySQL is most popular vault system and I want to learn how to use it :)
Then, first get a database before request the plugin...
Anyway, i need help about two thing. How do i get a string?
Also, lets say that i have in db the same steam id 2 times, but different values. How do i get those variables?
Which string?
Why would you have the same steam id twice on your database?
nevermind. did I need this part of the code:
[php]new Host[] = "hostname"
new User[] = "username"
new Pass[] = "password"
new Db[] = "database" [/pph]
nevermind. did I need this part of the code:
[php]new Host[] = "hostname"
new User[] = "username"
new Pass[] = "password"
new Db[] = "database" [/pph]
yes you need it. you need a database and put the information about database.
Anyway, sql isnt the best. It has advantages but also has disadvantages. The biggest advantage is that you will be able to make php scripts and show saved stuff in a website. If you dont need that, go use nvault or fvault because they are better.
Ant1Lamer
05-31-2022, 13:56
Can you tell me how to save kills in sql and how to load this kills ? and how to remove after a given period of time.
P.S: This plugin i cant to use "#include <csstats>" just to need to make "x" kills and after make this "x" kills they remove a given period of time
Do you just need the SQL or are you asking for code? For something simple like this, you could always use nVault, which includes the prune function to delete stuff after X time.
vBulletin® v3.8.7, Copyright ©2000-2024, vBulletin Solutions, Inc.