[Tutorial] How to Make a Command That Bans an Offline Player [ZCMD + y_ini + Sscanf]
#1

Hey guys today I'm gonna show you how to ban an offline(not connected) player from your server, this is very easy to do so I wanted to share it with you guys

Let's get started.

Requirments:

* ZCMD (Zeex)

* y_ini (******)

* Sscanf2 (******)

* Kush (For his tutorial) <==== You have to follow his tutorial first before you continue with me.

Now let me tell you what is ZCMD and y_ini.

ZCMD: ZCMD is a fast and simple command processor.

y_ini: y_ini is a fast and modern .ini file reading and writing system.

First of all add this at the top of your GameMode/FilterScript BUT under "#include <a_samp>":

pawn Code:
#include <zcmd>
#include <sscanf2>
#include <YSI\y_ini>


Sscanf Specifiers(Thanks to ******):

Code:
Specifier(s)			Name				Example values
	i, d			Integer				1, 42, -10
	c			Character			a, o, *
	l			Logical				true, false
	b			Binary				01001, 0b1100
	h, x			Hex				1A, 0x23
	o			Octal				045 12
	n			Number				42, 0b010, 0xAC, 045
	f			Float				0.7, -99.5
	g			IEEE Float			0.7, -99.5, INFINITY, -INFINITY, NAN, NAN_E
	u			User name/id (bots and players)	******, 0
	q			Bot name/id			ShopBot, 27
	r			Player name/id			******, 42
Now let's get in to the real thing!

First we are going to look at our Enum that we just did with Kush's tutorial.
It should look like this:

pawn Code:
enum pInfo
{
    pPass,
    pCash,
    pAdmin,
    pKills,
    pDeaths
}
new PlayerInfo[MAX_PLAYERS][pInfo];
What we are going to do is add another one variable and one string called "pBanned"(variable) and "BannedIP"(string) which is a string with the size of 22, like this:

pawn Code:
enum pInfo
{
    pPass,
    pCash,
    pAdmin,
    pKills,
    pDeaths,
    pBanned, //Here!
    BannedIP[22] //This one too :P
}
new PlayerInfo[MAX_PLAYERS][pInfo];
Go back to your OnPlayerDialog and find a line that looks like this:

pawn Code:
case DIALOG_REGISTER:
{
    if (!response) return Kick(playerid);
    if(response)
    {
        if(!strlen(inputtext)) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_INPUT, ""COL_WHITE"Registering...",""COL_RED"You have entered an invalid password.\n"COL_WHITE"Type your password below to register a new account.","Register","Quit");
        new INI:File = INI_Open(UserPath(playerid));
        INI_SetTag(File,"data");
        INI_WriteInt(File,"Password",udb_hash(inputtext));
        INI_WriteInt(File,"Cash",0);
        INI_WriteInt(File,"Admin",0);
        INI_WriteInt(File,"Kills",0);
        INI_WriteInt(File,"Deaths",0);
        INI_Close(File);

        SetSpawnInfo(playerid, 0, 0, 1958.33, 1343.12, 15.36, 269.15, 0, 0, 0, 0, 0, 0);
        SpawnPlayer(playerid);
        ShowPlayerDialog(playerid, DIALOG_SUCCESS_1, DIALOG_STYLE_MSGBOX,""COL_WHITE"Success!",""COL_GREEN"Great! Your Y_INI system works perfectly. Relog to save your stats!","Ok","");
    }
}
We wanna add the player's IP for futher use. It should look like this:

pawn Code:
case DIALOG_REGISTER:
{
    if (!response) return Kick(playerid);
    if(response)
    {
        if(!strlen(inputtext)) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_INPUT, ""COL_WHITE"Registering...",""COL_RED"You have entered an invalid password.\n"COL_WHITE"Type your password below to register a new account.","Register","Quit");
        new IP[22]; // Creating a new string called IP with the maximum length of 22.
        GetPlayerIp(playerid, IP, sizeof(IP)); // Here we are getting the Player's IP and storing it in our string "IP" with the maximum length of 22.
        new INI:File = INI_Open(UserPath(playerid));
        INI_SetTag(File,"data");
        INI_WriteInt(File,"Password",udb_hash(inputtext));
        INI_WriteInt(File,"Cash",0);
        INI_WriteString(File, "Ip", IP); // We're writing in the .ini file of the player a new line which will contain our string "IP", so it'll look like "Ip = IP String here". If my IP was for example "127.0.0.1" then it'll be "Ip = 127.0.0.1".
        INI_WriteInt(File,"Admin",0);
        INI_WriteInt(File,"Kills",0);
        INI_WriteInt(File,"Deaths",0);
        INI_Close(File);

        SetSpawnInfo(playerid, 0, 0, 1958.33, 1343.12, 15.36, 269.15, 0, 0, 0, 0, 0, 0);
        SpawnPlayer(playerid);
        ShowPlayerDialog(playerid, DIALOG_SUCCESS_1, DIALOG_STYLE_MSGBOX,""COL_WHITE"Success!",""COL_GREEN"Great! Your Y_INI system works perfectly. Relog to save your stats!","Ok","");
    }
}
Now after we got that out off of our way, we will make the command. Which will look like this:

pawn Code:
CMD:banofflineplayer(playerid, params[])
{
    new targetname[24], filestring[79];
    if(sscanf(params, "s[24]", targetname)) return SendClientMessage(playerid, -1, "Correct Usage: /banofflineplayer [Player's Name]");
    format(filestring, sizeof(filestring), "/Users/%s.ini", targetname);
    if(!fexist(filestring)) return SendClientMessage(playerid, -1, "Error: The player name you have chosen was not found in our system.");
    else
    {
        new INI:File = INI_Open(filestring);
        INI_SetTag(File, "data");
        INI_WriteInt(File, "Banned", 1);
        INI_Close(File);
        new done[128];
        format(done, sizeof(done), "You have banned %s", targetname);
        SendClientMessage(playerid,-1 , done);
    }
    return 1;
}
Now let me break that up for ya:

pawn Code:
new targetname[24], filestring[79];
Here we are creating a new string called "targetname" with the size of 24 which is the max characters a SA-MP name can have, and creating another string called "filestring" with the size of 79.

pawn Code:
if(sscanf(params, "s[24]", targetname)) return SendClientMessage(playerid, -1, "Correct Usage: /banofflineplayer [Player's Name]");
Here we are checking if the player entered the correct parameters of our command which is "/banofflineplayer [Player's Name]", if he didin't enter the correct parameters it will give him an error.

pawn Code:
format(filestring, sizeof(filestring), "/Users/%s.ini", targetname);
Here we are formatting our "filestring" to the directory of our User Files, and you can see that I have typed in %s which means a string and if you look more to the right you will see that I typed in "targetname" what this basicly means is that our %s(String) will get replaced with our "targetname" string which we just typed in. "/banofflineplayer [Player's Name]", our parameter "targetname" will get replaced with our text which is something like this: "/banofflineplayer gta" , "gta" will be inserted to our string "targetname". So our %s will get replaced with "gta".

pawn Code:
if(!fexist(filestring)) return SendClientMessage(playerid, -1, "Error: The player name you have chosen was not found in our system.");
Now here we are checking if our string "filestring" exists, remember when we formated it to "/Users/%s.ini"? Well now we can call "filestring" a directory for our "targetname". So we are basicly checking to see if the directory in "filestring" exists, if not it will return an error.

pawn Code:
else
This means that if all of the errors above are false or don't apply to you then you can continue with the rest of the command.

pawn Code:
new INI:File = INI_Open(filestring);
Here we are opening our "filestring" (The directory of "/Users/%s.ini"). In other words we're opening the .ini file of the player. Which containts all of his status.

pawn Code:
INI_SetTag(File, "data");
Setting the tag of the .ini file. Setting tags in Y_Ini is very important!

More explanation on that in the /unban command below!

pawn Code:
INI_WriteInt(File, "Banned", 1);
Now here we are writing a new entry with the name of "Banned" and it has an integer with the value of 1 which means true.

pawn Code:
INI_Close(File);
Closing our .ini file.

pawn Code:
new done[128];
Creating a new string with the name of "done" and its size is 128.

pawn Code:
format(done, sizeof(done), "You have banned %s", targetname);
formatting our "done" string. You noticed that I used %s in there? I'll tell you why, if you look above you will see that we have "new targetname[24]" which means that we created a new string called "targetname" with the size of 24. So what will happen is that our %s will get replaced with our "targetname" string. For example: /banofflineplayer Gta ."Gta" will be inserted to our "targetname" string, so now it should send our formated "done" string like this: "You have banned Gta" with no quotient marks.

pawn Code:
SendClientMessage(playerid,-1, done);
Sending our formated "done" string to ourself(playerid).

pawn Code:
return 1;
Returning 1 for the command to work.

Now let's make something that checks to see if the player's User Account.ini contains "Banned = 1".

Add this at the top of your OnPlayerRequestClass:

pawn Code:
if(PlayerInfo[playerid][pBanned] == 1)//Checking if the user's file contains "Banned = 1", if that's true we continue if not we die :D
{
    Ban(playerid); //Banning the player. I like to not send a Message saying that you have been banned..etc so the hacker doesn't know why it said "Server closed the connection" and changes his IP and the same thing happens and his new IP gets banned, stealthy shit :p
}
Now remember in Kush's tutorial you made a stock with the name of "LoadUser_data" that loads the user? Well I want you to locate it and add the following line:

pawn Code:
INI_Int("Banned", PlayerInfo[playerid][pBanned]);
So your stock "LoadUser_data" should now look like this:

pawn Code:
public LoadUser_data(playerid,name[],value[])
{
    INI_Int("Password",PlayerInfo[playerid][pPass]);
    INI_Int("Cash",PlayerInfo[playerid][pCash]);
    INI_Int("Banned", PlayerInfo[playerid][pBanned]);//Well basicly we are getting the entry "Banned" from the user's .ini file and storing it in "PlayerInfo[playerid][pBanned]" variable.
    INI_Int("Admin",PlayerInfo[playerid][pAdmin]);
    INI_Int("Kills",PlayerInfo[playerid][pKills]);
    INI_Int("Deaths",PlayerInfo[playerid][pDeaths]);
    return 1;
}
Now for the /unbanofflineplayer Command!

It will look like this:

pawn Code:
CMD:unbanofflineplayer(playerid, params[])
{
    new string[128],tname[24];
    if(sscanf(params, "s[24]", tname)) return SendClientMessage(playerid,-1,"Correct Usage: /unbanofflineplayer [Player Name] ");
    new filestring[79];
    format(filestring, sizeof(filestring), "/Users/%s.ini", tname);
    if(!fexist(filestring)) return SendClientMessage(playerid,Lime, "The name you've chosen was not found in our database ");
    else
    {
        new INI:File = INI_Open(filestring);
        INI_SetTag(File, "data");
        INI_WriteInt(File, "Banned",0);
        INI_Close(File);
        INI_ParseFile(filestring, "LoadIP_%s", .bExtra = true , .extra = playerid);
        new cmdstring[44];
        format(cmdstring, sizeof(cmdstring), "unbanip %s", PlayerInfo[playerid][BannedIP]);
        SendRconCommand(cmdstring);
        SendRconCommand("reloadbans");
        new done[128];
        format(done, sizeof(done),"You have successfully unbanned %s", tname);
        SendClientMessage(playerid, -1,done);
    }
    return 1;
}
Explanation:

pawn Code:
new string[128],tname[24];
Creating a new string called "string" and another called "tname". What Are Strings?


pawn Code:
if(sscanf(params, "s[24]", tname)) return SendClientMessage(playerid,-1,"Correct Usage: /unbanofflineplayer [Player Name]");
Here we're checking if the parameters of the command contains the Player Name. If not, it'll return us this error: "Correct Usage: /unbanofflineplayer [Player Name]".
So if I use "/unbanofflineplayer" only, it'll give me an error. Now away from the error side. If I enter "/unbanofflineplayer gtakillerIV", our tname will be assigned to gtakillerIV. That means if I use tname in anything for example like: printf("%s", tname); It will print in the console "gtakillerIV".
You're probably wondering what "s[24]" means, it means that our 1st parameter after the command "," which is tname is a string with the size of 24(maximum charactes in a SA-MP name).


pawn Code:
new filestring[79];
We are creating a new string called "filestring" with the size of 79. Means it can only take 79 charactes. We will use this later on for our User's directory.


pawn Code:
format(filestring, sizeof(filestring), "/Users/%s.ini", tname);
Now here we're formatting our string "filetsring" with our User's Directory which is "/Users/%s.ini". %s stands for String. Alright so now, if I go ingame and type in "/unbanofflineplayer gtakillerIV" the "filestring" string will be formated as: "/Users/gtakillerIV.ini".
This is pretty much it, thanks for reading I hope I have did a good job in explaining.


pawn Code:
if(!fexist(filestring)) return SendClientMessage(playerid,Lime, "The name you've chosen was not found in our database ");
In the last line we formated our string "filestring" to be a directory of our "tname"'s string, so now "filestring" is our directory location of our Accounts folder. So here we're checking to see if the directory "filestring" exists, if not it'll return an error. Ex: If I go ingame and type in "/unbanofflineplayer gtakillerIV" our string "tname" will be set to "gtakillerIV" after that our directory string aka "filestring" will be formated as "/Users/%s.ini" if our account doesn't exist, we'll get an error.


pawn Code:
else
If all of the above is FALSE in other words doesn't correspond to our situation we will continue with the next block of codes.


pawn Code:
new INI:File = INI_Open(filestring);
Here we are opening our .ini file using our directory "filestring"(/Users/%s.ini). If I go ingame and type in "/unbanofflineplayer gtakillerIV", our "filestring" will be formated as "/Users/gtakillerIV" and this line here will open our .ini file("/Users/gtakillerIV.ini")


pawn Code:
INI_SetTag(File, "data");
Here we're setting the tag of the .ini file which will look like [data] inside the .ini file. It's very important to set a tag, else it won't replace the current value of "Banned". Remember that Tags have to be the same, so for example if I set the tag to "test123" it will create a new tag which will look like [test123] and above it our [data] tag which has the "Banned" value. .ini file will look like:
pawn Code:
[data]
Banned = 1;
[test123]
Banned = 0;
As you can see instead of replacing the "Banned = 1" it created a new line with a new tag"[test123]".


pawn Code:
INI_WriteInt(File, "Banned",0);
Here we are writing or if it's currently in the .ini file we will replace it with the "0". So the .ini file should look like:
pawn Code:
[data]
Banned = 0;

pawn Code:
INI_Close(File);
Here we are closing our .ini and saving it.

Alright now add this anywhere in your script:

pawn Code:
public LoadIP_data(playerid, name[], value[]) //Creating a new Public function for use later.
{
    INI_String("Ip", PlayerInfo[ playerid ][ BannedIP ], 33); //Loading the string "Ip", and assigning it to our string "BannedIP", with the maximum size of 33.
    return 1; //Returning 1 for it to work.
}

pawn Code:
INI_ParseFile(filestring, "LoadIP_%s", .bExtra = true , .extra = playerid);
Here we are loading the Public Function "LoadIP_data". We're also passing an extra variable called "playerid". What will happen is that our "BannedIP" string will be assigned to the target name's IP address. So if "gtakillerIV"'s IP was "127.0.0.1" our BannedIP string will be set to "127.0.0.1".

pawn Code:
new cmdstring[44];
Here we are creating a new String called "cmdstring" with the maximum length of 44.


pawn Code:
format(cmdstring, sizeof(cmdstring), "unbanip %s", BannedIP[playerid]);
Here we are formatting our "cmdstring" that we created earlier with the data "unbanip %s" again %s stands for string. %s will be replaced with our string data of BannedIP[playerid]. So if "gtakillerIV"'s IP is "127.0.0.1" our BannedIP[playerid] string will be set to "127.0.0.1" and our "cmdstring" string will be formated as "unbanip 127.0.0.1".


pawn Code:
SendRconCommand(cmdstring);
Here we are sending a RCON command which is the data of our string "cmdstring". If "gtakillerIV"'s IP was "127.0.0.1" then our "cmdstring" will be "unbanip 127.0.0.1" so it will be like doing "SendRconCommand("unbanip 127.0.0.1");".


pawn Code:
SendRconCommand("reloadbans");
Reloading our samp.ban file. In other words we're reloading our bans.


pawn Code:
new done[128];
Creating a new string called "done" with the maximum characters of 128, which is the maximum length of a message in SA-MP.


pawn Code:
format(done, sizeof(done),"You have successfully unbanned %s", tname);
Here we are formatting our "done" string to "You have successfully unbanned %s". If I entered "/unbanofflineplayer gtakillerIV" our "done" string will be formated as "You have successfully unbanned gtakillerIV".


pawn Code:
SendClientMessage(playerid, -1,done);
Sending our string "done" to ourself.


My second Tutorial, first one sucked, so I hope this one is good.

Thank you.
Reply
#2

Nice,Good job
Reply
#3

Thanks
Reply
#4

Not bad for persons what doesn't know how to do this
Reply
#5

True, I just did this Tutorial since I couldn't find one when I was looking for one so I did this Tutorial to help others that have the same problem.

Thanks.
Reply
#6

Great tutorial, well explained.

You should make a /unban counter part.

pawn Code:
INI_WriteInt(File, "Banned", 0);
Reply
#7

Thanks so much, it's useful.
Reply
#8

Quote:
Originally Posted by JhnzRep
View Post
Great tutorial, well explained.

You should a /unban counter part.

pawn Code:
INI_WriteInt(File, "Banned", 0);
I thought of that but the problem is that the player gets banned, what I mean is when he connects we check if "Banned = 1" if that is true he will get banned so the samp.ban file will store his IP, so I have to find a way to remove the IP from the samp.ban file too.

EDIT:

Hmm I guess I found an idea

I might make the command now and test it.

Quote:
Originally Posted by Austain_Jake
View Post
Thanks so much, it's useful.
Your welcome
Reply
#9

Quote:
Originally Posted by gtakillerIV
View Post
I thought of that but the problem is that the player gets banned, what I mean is when he connects we check if "Banned = 1" if that is true he will get banned so the samp.ban file will store his IP, so I have to find a way to remove the IP from the samp.ban file too.

EDIT:

Hmm I guess I found an idea

I might make the command now and test it.



Your welcome
I know a way to unban the IP from samp.ban, but I don't know how to load the IP value.
Reply
#10

That's what I'm working on, I'm trying to learn from this thread:

https://sampforum.blast.hk/showthread.php?tid=386144

Easy to read stuff yea?
Reply
#11

Good job bro
Reply
#12

Nice TUT Useful For those using Y_ini
Reply
#13

Nice.
Reply
#14

Useful tutorial, but,
Y_INI very fast than SII ?
Reply
#15

Quote:
Originally Posted by CoDeZ
Посмотреть сообщение
Good job bro
Thanks bro

Quote:
Originally Posted by Deron_Green
Посмотреть сообщение
Nice TUT Useful For those using Y_ini
Thanks.

Quote:
Originally Posted by Lordz™
Посмотреть сообщение
Nice.
Thanks Lordz™

Quote:
Originally Posted by [Full]Garfield[XDB]
Посмотреть сообщение
Useful tutorial, but,
Y_INI very fast than SII ?
Thanks, and yep y_ini is faster than SII.
Reply
#16

Added /unbanofflineplayer command. Very sorry for delay guys.

If you find any mistake please tell me, thanks.
Reply
#17

very handy command this does it block the ip as well so they cant create new account in differnt name ??
Reply
#18

thnxx for it man
Reply
#19

Quote:
Originally Posted by DaveGG
Посмотреть сообщение
very handy command this does it block the ip as well so they cant create new account in differnt name ??
Yes.

Quote:
Originally Posted by Arpit_Singh
Посмотреть сообщение
thnxx for it man
You're welcome.
Reply
#20

nice.
Reply


Forum Jump:


Users browsing this thread: 7 Guest(s)