22.09.2013, 09:53
Good day.
This is a tutorial on how to make a ban system using MySQL and unix timestamps. (Timed)
There may be better ways, but this is how I roll.
NOTE: Please read it carefully before asking questions because this is not a copy paste code tutorial, you need to work your way towards making it. Hence, a tutorial.
Steps:
1) Create an enum for player to store data about his bans in
2) Create a MySQL table to store that data.
3) Retrieve it on the event of the player connecting and allow/disallow entry
1) Creating an enum for players.
Simple enough. You can learn about enums if you don't know, here.
What we did is create MAX_PLAYERS amount of copies of those variables for each indivisual entity. Something like OOP. (yeah?)
Let's create the table for banning the player now.
Please read about SQL syntax online, here.
That's done then, creating the table.
Now we need to insert player NAMES when they register. I ASSUME you have got a register system in place.
Now we are done inserting the player's name in the table!
We can start creating the BAN command now.
Okay. Done with ban command. It should now update the values of the target.
NOTE: Make sure you save them again in OnPlayerDisconnect.
Last step.
OnPlayerConnect, should we allow entry?
Okay now the function.
Now we create the function CheckForExistingBans.
That's it. You can add all other modifications as per your need. These are the basic components you need to get started.
READ ABOUT UNIX TIMESTAMPS HERE.
BUGS:
Please report bugs immediately if you spot one.
I accept that there could be logical as well as syntactical bugs!
Thank you.
This is a tutorial on how to make a ban system using MySQL and unix timestamps. (Timed)
There may be better ways, but this is how I roll.
NOTE: Please read it carefully before asking questions because this is not a copy paste code tutorial, you need to work your way towards making it. Hence, a tutorial.
Steps:
1) Create an enum for player to store data about his bans in
2) Create a MySQL table to store that data.
3) Retrieve it on the event of the player connecting and allow/disallow entry
1) Creating an enum for players.
pawn Code:
enum pI
{
pBANNED, // Values 0 or 1 - 1 means banned
pBANNEDfor[20], // The reason for being banned?
pBANNEDby[MAX_PLAYER_NAME], // The ADMIN who banned this player
pBANNEDtime, // the timestamp of being banned. Not necessary but useful for showing stuff.
pUNBANtime // the time to be unbanned
}
new pINFO[MAX_PLAYERS][pI];
What we did is create MAX_PLAYERS amount of copies of those variables for each indivisual entity. Something like OOP. (yeah?)
Let's create the table for banning the player now.
Please read about SQL syntax online, here.
pawn Code:
new conn_HANDLE; // Global variable to store connection handle value in.
public OnGameModeInit()
{
#define SQL_HOST "localhost"
#define SQL_USER "root"
#define SQL_PASS ""
#define SQL_DATABASE "my_database"
// Defining the specifics for the mysql connection. Usually are the above for a server using localhost wamp server.
conn_HANDLE = mysql_connect(SQL_HOST, SQL_USER, SQL_DATABASE, SQL_PASS);
// connecting..
// you can include checks like if(mysql_ping() > 1) to see if the connection was successful, I am skipping that!
mysql_function_query(conn_HANDLE, "CREATE TABLE IF NOT EXISTS `playerbans`(username VARCHAR(24), pBANNED INT(1), pBANNEDfor VARCHAR(20), pBANNEDby VARCHAR(24), pBANNEDtime INT(30), pUNBANtime INT(30) )", false, "", "");
// we create the table, called `playerbans` and create columns like USERNAME of character type, max length 24, pBANNED of just 1 (stores only 0 or 1) and so on.
// "false" specifies that we don't need to store returned data
// "" "" mean that we don't need any callback to store returned data (no data!)
return 1;
}
Now we need to insert player NAMES when they register. I ASSUME you have got a register system in place.
pawn Code:
stock YourRegisterSystemStock_WhereYouRegisterAPlayer(playerid)
{
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid, name, MAX_PLAYER_NAME);
// Getting the name of the guy
new string[128];
format(string, sizeof(string), "INSERT INTO `playerbans`(username, pBANNED, pBANNEDby, pBANNEDfor, pBANNEDtime, pUNBANtime) VALUES( '%s', 0,' ',' ', 0, 0)", name);
// we insert the player's name in the table!
mysql_function_query(conn_HANDLE, string, false, "", "");
// Again we don't need to process returned data, so false.
return 1;
}
We can start creating the BAN command now.
pawn Code:
CMD:ban(playerid, params[])
{
new target_id, hours, minutes, seconds, reason[20], name[MAX_PLAYER_NAME];
// new variables, purpose stated below.
if(!IsPlayerAdmin(playerid)) return SendClientMessage(playerid, -1, "SERVER: UNKNOWN COMMAND.");
// You ain't logged into RCON, dude!
if(sscanf(params, "uddds[20]", target_id, hours, minutes, seconds, reason)) return SendClientMessage(playerid, -1, "USAGE: /ban (playerid) (hours) (mins) (secs) (reason)");
// We insert values the command executor typed after ban in the respective variables.
// u -> player -> target_id - the player to be banned
// d -> hours -> hours to be banned
// s -> reason (string) -> 20 max chars.
// We return him the USAGE string if all parameters were not filled.
if(!IsPlayerConnected( target_id ) ) return SendClientMessage(playerid, -1, "ERROR: Requested player is offline.");
{
// okay, he's admin, he has typed correctly.
GetPlayerName(playerid, name, MAX_PLAYER_NAME);
pINFO[target_id][pBANNED] = 1; // okay, now set the ban status of target to 1
pINFO[target_id][pBANNEDtime] = gettime(); // returns a timestamp of the current moment!
format( pINFO[target_id][pBANNEDfor], 20, "%s", reason ); // Now pBANNEDfor contains the reason.
format( pINFO[target_id][pBANNEDby], MAX_PLAYER_NAME, "%s", name); // the person who banned the target
// the main part. When is he going to be unbanned?
new total_banned_seconds_from_now = seconds + ( minutes * 60 ) + (hours * 60 * 60);
// now the variable contains the total seconds the target is to be banned, from now!
// If you don't know why we multipled by 60, go back to school!
pINFO[target_id][pUNBANtime] = total_banned_seconds_from_now + gettime();
// So if I typed /ban player 0 1 50 TEST, current gettime() would be datestamp.
// let datestamp be 124124. I need to ban 'player' 1 minute and 50 seconds.
// according to calculations, that is 110 seconds. Hence, the timestamp when the 'player' player is to be unbanned is
// 124124 + 110 = 124230 !
// Let's update the target_id's table.
new query[200], TARGETname[MAX_PLAYER_NAME];
GetPlayerName(target_id, TARGETname, 24);
format(query, sizeof(query), "UPDATE `playerbans` SET pBANNED = 1, pBANNEDfor = '%s', pBANNEDby = '%s', pBANNEDtime = %d, pUNBANtime = %d WHERE username = '%s'" reason, name, gettime(), pINFO[target_id][pUNBANtime], TARGETname);
mysql_function_query(conn_HANDLE, query, false, "", "");
SendClientMessage(target_id, -1, "You have been banned.");
SendClientMessage(playerid, -1, "You have banned the requested player successfully.");
// You can format and add effects like gametext, sending to jail, freezing, etc. I am keeping it simple.
KickWithDelay( target_id );
// I assume KickWithDelay as the function where you set a timer to kick, etc.
// The link for it is https://sampwiki.blast.hk/wiki/Kick, look in the example section.
}
return 1;
}
NOTE: Make sure you save them again in OnPlayerDisconnect.
Last step.
OnPlayerConnect, should we allow entry?
pawn Code:
public OnPlayerConnect( playerid )
{
new query[70], name[24];
GetPlayerName(playerid, name, 24);
format(query, 70, "SELECT * FROM `playerbans` WHERE username = '%s'", name); // select ALL from..
// We select the player row!
mysql_function_query(conn_HANDLE, query, true, "OnPlayerRowCheck", "d", playerid);
// We will now check under the callback OnPlayerRowCheck to see if his row exists.
return 1;
}
pawn Code:
forward public OnPlayerRowCheck( playerid );
public OnPlayerRowCheck( playerid )
{
new rows, fields;
cache_get_data(rows, fields, dbHANDLE);
// get amount of rows!
if(rows)
{
// Okay, he has registered and has a row to himself in the mysql database.
new number[25];
cache_get_field_content(0, "pBANNEDfor", number), format(pINFO[playerid][bannedFOR], 20, "%s", number);
cache_get_field_content(0, "pBANNEDby", number), format(pINFO[playerid][bannedBY], 25, "%s", number);
cache_get_field_content(0, "pUNBANtime", number), pINFO[playerid][unBANTIME] = strval(number);
cache_get_field_content(0, "pBANNEDtime", number), pINFO[playerid][bannedTIME] = strval(number);
cache_get_field_content(0, "pBANNED", number), pINFO[playerid][banned] = strval(number);
// Okay, now we got the data correctly!
CheckForExistingBans( playerid );
}
return 1;
}
pawn Code:
stock CheckForExistingBans( playerid )
{
if( pINFO[playerid][banned] == 1 )
{
if( gettime() > pINFO[playerid][pUNBANtime] ) // that is, unban time has already gone by, he should be unbanned.
{
pINFO[playerid][banned] = 0;
SendClientMessage(playerid, -1, "You have been unbanned.");
// reset all other variables to 0 and blank.
}
else // he's still banned
{
SendClientMessage(playerid, -1, "You are still banned!");
// Now we tell him HOW much time is remaining for the ban to get over.
new diff_secs = ( pINFO[playerid][pUNBANtime] - gettime() );
new remain_hours = floatround( diff_secs / 60 * 60 ); // unbantime - gettime = seconds remaining.
// dividing by 60 square, we get hours remaining. floatround to be sure.
new remain_mins = floatround( diff_secs / 60 );
// doing the same thing, just dividing by 60!
new remain_secs = diff_secs % 60;
// modulo operator gives the remainder after the closest quotient. So if 70 seconds are remaining,
// 60 + 10 = 70. That means 1 minute and 10 seconds remaining.
new string[128];
format(string, 128, "TIME REMAINING TILL UNBAN: %d hours, %d minutes and %d seconds.", remain_hours, remain_mins, remain_secs);
SendClientMessage(playerid, -1, string);
// Now we kick that player with delay.
KickWithDelay( playerid );
}
return 1;
}
}
READ ABOUT UNIX TIMESTAMPS HERE.
BUGS:
Please report bugs immediately if you spot one.
I accept that there could be logical as well as syntactical bugs!
Thank you.