07.12.2014, 15:21
Temporary Ban Command
I searched for temporary ban command tutorials on the forums, and I struggled to find any. I'm not sure if this is my fault for not using the search tools properly, or if there actually aren't any tutorials, but regardless, I'm going to attempt to teach you how to create a very simple temporary ban system using ZCMD, sscanf and MySQL. By no means is this the most efficient way of creating a banning system, but it works! Also, just a quick note, this tutorial is aimed at people who have at least some understanding of MySQL and how to manage a MySQL database and SA-MP (pawn) coding (& using phpMyAdmin etc.). Anyway, let's get started.Includes
First of all, we need a few includes, and the plugins that go with them. You can download them all here:
ZCMD
sscanf
MySQL - I'm using R6 for this, as I'm not using threaded queries. If you know how to use threaded queries, by all means do so! (Download link has broken and I cannot find another download... sorry!)
I'm going to assume you know how to where to put the include and plugin files.
Now, we need to include them at the top of our script under the a_samp include:
pawn Код:
#include <a_samp>
#include <sscanf2>
#include <zcmd>
#include <a_mysql>
pawn Код:
plugins sscanf mysql
Coding
First, we need to tell our script to connect to the MySQL database. You may have already done this if you're using a MySQL-based gamemode, so feel free to move on.
I'm going to connect to the database under OnGameModeInit:
pawn Код:
public OnGameModeInit()
{
mysql_debug(); // I'm enabling the debug so if anything goes wrong, we can check it in the log file.
mysql_connect("localhost", "root", "tutorial", ""); //Connecting to the database, using mysql_host, mysql_user, mysql_database and mysql_password.
if(mysql_ping() < 1) //I'm checking the ping of the server to the MySQL server. If this is 0, the connection has failed.
{
print("MYSQL CONNECTION FAILED!");
}
else
{
print("MYSQL CONNECTION SUCCESSFUL!"); //Otherwise, the connection was successful.
}
Now, we can create the table in the database. We need to go to our MySQL database in phpMyAdmin (or another GUI if you don't use phpMyAdmin) and create a new table called "bans" with 7 columns:
We need to name them as follows:
Make sure to tick the auto increment box on ban_id so each ban has its own unique ID, you'll see why later.
Now, onwards to the command.
I'm going to use ZCMD and sscanf to create my command at the bottom of the gamemode file.
pawn Код:
CMD:tempban(playerid, params[])
{
new banner[MAX_PLAYER_NAME], banned[MAX_PLAYER_NAME], bannedid, reason[25], hours, string[400], secs, unbants, ip[16], query[180];
- banner - the name of the administrator who performed the command
- banned - the name of the player that is being banned
- bannedid - the ID of the player that is being banned
- reason - the reason, entered by the admin, for the ban
- hours - the amount of hours the player will remain banned for
- string - a string to hold the messages that will be sent to show the ban
- secs - the hours converted to seconds
- unbants - the timestamp for the time and date the player will be unbanned
- ip - the player's ip address
- query - the mysql query that we'll format
Now we need to add some checks that will run when the administrator performs the command:
pawn Код:
if(!IsPlayerAdmin(playerid) && pData[playerid][Level] < 2) return SendClientMessage(playerid, ERROR, "You do not have sufficient permissions to use this command."); //this is just my admin check, yours may be different.
if(sscanf(params, "uds[25]", bannedid, hours, reason)) return SendClientMessage(playerid, -1, "Usage: /tempban [player name/ID] [hours] [reason]"); // here, we're checking if the administrator entered the command correctly. "u" is a player name or ID, "d" is the amount of hours as an integer, and "s[25]" is the reason.
if(!IsPlayerConnected(bannedid)) return SendClientMessage(playerid, -1, "Invalid player name/ID."); //checking if the player that the admin is trying to ban is connected to the server
if(pData[playerid][Level] < pData[bannedid][Level]) return SendClientMessage(playerid, -1, "You cannot ban someone with a higher level than you!"); //I don't allow admins to ban those with higher levels than their own.
if(strlen(reason) < 3 || strlen(reason) > 24) return SendClientMessage(playerid, -1, "Your reason must be between 3 and 24 characters."); //limiting the reason length to 3-24 characters
if(hours < 12 || hours > 720) return SendClientMessage(playerid, -1, "Ban hours are between 12 and 720 hours"); //making sure the ban duration is no shorter than 12 hours and no longer than 30 days
We need to save the administrator and the player's names in order to present them in a message later on, as well as the player's IP address, so I'll get it out of the way now:
pawn Код:
GetPlayerName(playerid, banner, sizeof(banner));
GetPlayerName(bannedid, banned, sizeof(banned));
GetPlayerIp(bannedid, ip, sizeof(ip));
pawn Код:
secs = hours*3600
Now I can work out the unix timestamp at the time that the player will be unbanned by adding the current unix time to the amount of seconds that the player will be banned for. If you don't know what a unix timestamp is, it is the amount of seconds that have passed since the 1st of January, 1970.
pawn Код:
unbants = gettime()+ secs;
Now it's time to save our information to the MySQL database. We need to format the "query" variable:
pawn Код:
format(query, sizeof(query), "INSERT INTO `bans` (ban_id, player, ip, admin, reason, ban_time, unban_time) VALUES ('0', '%s', '%s', '%s', '%s', %d, %d)",
banned, ip, banner, reason, gettime(), unbants);
mysql_query(query);
pawn Код:
format(string, sizeof(string), "You've been temporarily banned.\n\n{FFFFFF}Staff member: %s\nReason: %s", banner, reason);
ShowPlayerDialog(bannedid, 678, DIALOG_STYLE_MSGBOX, "Banned!", string, "Close", "");
Also, I want to tell everybody else in the server that the person has been banned:
pawn Код:
format(string, sizeof(string), "%s(%d) has banned %s(%d) for %d hours for: %s", banner, playerid, banned, bannedid, hours, reason);
SendClientMessageToAll(-1, string);
pawn Код:
SetTimerEx("KickEx", 500, false, playerid, "i");
pawn Код:
forward KickEx(playerid);
public KickEx(playerid)
{
Kick(playerid);
return 1;
}
Ban Checking
When a player connects to the server, we need to check if their IP address is in our ban table, and if it is, we need to check if their ban has expired or if they need to remain banned.
First, under OnPlayerConnect, we'll declare two variables:
pawn Код:
new banquery[180], ip[16];
pawn Код:
GetPlayerIp(playerid, ip, 16);
pawn Код:
format(banquery, sizeof(banquery), "SELECT unban_time FROM `bans` WHERE ip = '%s'", ip);
mysql_query(banquery);
mysql_store_result();
pawn Код:
if(mysql_num_rows() != 0) //if an unban time was found with their ip address
{
new unbantimestamp = mysql_fetch_int(); //get the timestamp from the database
if(unbantimestamp > gettime()) //if the unban time hasn't been reached yet
{
SendClientMessage(playerid, -1, "You're banned from this server.");
SetTimerEx("KickEx", 500, false, playerid, "i");
}
}
You could also, using your knowledge gained from this tutorial, create an unban command which deactivates bans, hence the unique ban IDs.
Well, that's basically it. I don't think I've forgotten anything, but feel free to leave a reply if there's something I didn't explain very well. This is my first tutorial afterall.
Thanks.