[Tutorial] Making an Admin Script with dini!
#1

Introduction:
Hey today I will be showing you all how to create an entire admin system using dcmd and dini. This admin system will conclude of a register system and a few commands, I will try and go through everything in as much detail as I can, so you can understand everything better.

Getting Started:
First off your going to want to get some small defines out of the way, First you need to include dini so below #include <a_samp> you need to write #include <dini>
once you have done that you will need dcmd in your script so add this below #include <a_samp>:
pawn Код:
#define dcmd(%1,%2,%3) if (!strcmp((%3)[1], #%1, true, (%2)) && ((((%3)[(%2) + 1] == '\0') && (dcmd_%1(playerid, ""))) || (((%3)[(%2) + 1] == ' ') && (dcmd_%1(playerid, (%3)[(%2) + 2]))))) return 1
Then you need to get some colour defenitions out of the way, the colour defenitions are just so we dont have to remember the HEX colour code.
pawn Код:
#define GREY 0xAFAFAFAA
#define GREEN 0x33AA33AA
#define YELLOW 0xFFFF00AA
#define WHITE 0xFFFFFFAA
#define LIGHTBLUE 0x33CCFFAA
#define ORANGE 0xFF9900AA
Now that we have done all that we need to create an enum to store all our variables in, when creating an admin script it is alot more efficient to use an enum when creating multiple variables, add this somewhere on top of your script, but not in a callback!
pawn Код:
enum gPInfo
{
    Logged,
    Regged,
    Level
};
new PInfo[MAX_PLAYERS][gPInfo];
Great! now that we have that we can get started! your doing fine, now you should have one warning saying, "symbol is never used: "PInfo", but just ignore it we will get to that right away, to get rid of that awful warning go down to your OnPlayerConnect callback and add this:

pawn Код:
PInfo[playerid][Logged] = 0;
    PInfo[playerid][Regged] = 0;
    PInfo[playerid][Level] = 0;
This will set the variables to 0 which means not registered not logged and level 0, don't worry, we will make the set to our correct level in the /login command.

Now we will get to use dini for the first time, add this underneath the lines you just added:

pawn Код:
new n[MAX_PLAYER_NAME], file[256];
    GetPlayerName(playerid,n,sizeof(n));
What n[MAX_PLAYER_NAME] is, is its a variable we will use to store the players name in when he/she connects, file will be the location of where you want your files to be saved to, We have to use GetPlayerName to receive the players name when they connect, now that you have that, we will need to format the file so it reads it from the area that you want it to, underneath what you just wrote add:
pawn Код:
format(file,sizeof(file),"MyAdmin/Users/%s.txt",n);
this will read file as the area, MyAdmin/Users/%s.txt so now you need to go into your scriptfiles folder and create a folder called "MyAdmin", then inside that folder create another folder called "Users", make sure you use capitals for the first letter Just like I did ^.

Now where getting to the part where dini actually reads it and determines whether the player is registered or not, underneath your last line add this:
pawn Код:
if(dini_Exists(file))
    {
        SendClientMessage(playerid,LIGHTBLUE,"You are registered, Please /login!");
        PInfo[playerid][Regged] = 1;
        PInfo[playerid][Logged] = 0;
        return 1;
    }
this will check if the file which you formatted just before exists, if it exists it will order you to login and it will set the variables to Registered but not logged in, which is what we want, now the opposite:
pawn Код:
if(!dini_Exists(file))
    {
        SendClientMessage(playerid,LIGHTBLUE,"You are not registered, Please /register!");
        PInfo[playerid][Regged] = 0;
        PInfo[playerid][Logged] = 0;
        return 1;
    }
the "!"before the function is used like an opposite, it checks if the file doesn't exist, if it doesn't it sets both variables to 0 and instructs you to /register.

Now where one step away from creating the register and login commands, go to OnPlayerDisconnect and add this:

pawn Код:
new n[MAX_PLAYER_NAME], file[256];
    GetPlayerName(playerid,n,sizeof(n));
    format(file,sizeof(file),"MyAdmin/Users/%s.txt",n);
    PInfo[playerid][Logged] = 0;
             if(dini_Exists(file))
             {
                 dini_IntSet(file,"Logged",0);
                 return 1;
             }
if you have been listening you should already know what this piece of code does, if not, we get the players name, format the file location and check if the file exists, if it does exists we will edit the inside of the file "Logged" to 0
to show that he is not logged in...

Creating the Register/Login commands!
Now your halfway there! now creating the commands couldn't be easier!

go to your OnPlayerCommandText callback and add this:
pawn Код:
new cmd[256], idx;
    cmd = strtok(cmdtext, idx);
    dcmd(register,8,cmdtext);
Now we can add the commands, Lets start with the /register command:

pawn Код:
dcmd_register(playerid,params[])
{
    new file[256],n[MAX_PLAYER_NAME];
    GetPlayerName(playerid,n,MAX_PLAYER_NAME);
    format(file,sizeof(file),"MyAdmin/Users/%s.txt",n);
add that somewhere in your script, But not in a callback! that is just getting all the information to continue on with the command, now add this underneath it:
pawn Код:
if(dini_Exists(file)) return SendClientMessage(playerid,YELLOW,"You are already registered!");
    if(PInfo[playerid][Regged] == 1) return SendClientMessage(playerid,LIGHTBLUE,"You are already registered!");
    if(PInfo[playerid][Logged] == 1) return SendClientMessage(playerid,ORANGE,"You are already registered, and logged in!");
This will detect all the posibilites for the command to screw up, for example if the player is registered it will send an error or if they player is logged in it will send the error or if the file already exists in the database it will send the error, now we have to detect if the string length is empty (if the player types /register by itself)
add this underneath what you just added:
pawn Код:
if(strlen(params))
    {
        if(!dini_Exists(file))
        {
that just confirms that if the player string is not empty and that file does not exist which is what we want, now we can get to creating the file, add underneath that:

pawn Код:
dini_Create(file);
            dini_Set(file,"Password",params);
            dini_IntSet(file,"Regged",1);
            dini_IntSet(file,"Logged",0);
            dini_IntSet(file,"Level",0);
            SendClientMessage(playerid,LIGHTBLUE,"Congratulations, you have just registered, please /login");
            PInfo[playerid][Regged] = 1;
            return 1;
        }
in dcmd, when we are creating a command with only 1 parameter we can directly use "params" like we did there.
now we just have to add the error message for strlen(string length), so add this underneath that command:
pawn Код:
}
    else
    {
        SendClientMessage(playerid,GREY,"USAGE: /register <Password>");
        return 1;
    }
    return 1;
}
there we go, theres the else statement which is similiar to the "!" symbol it pretty much does the opposite, so we have that error message then we return one, congratulations you have just created your register command, now we need to create a login command!


Go back to your OnPlayerCommandText callback and add:

pawn Код:
dcmd(login,5,cmdtext);
underneath the other one

now we can get started on the login command underneath the register command add:

pawn Код:
dcmd_login(playerid,params[])
{
    new file[256],n[MAX_PLAYER_NAME];
    GetPlayerName(playerid,n,MAX_PLAYER_NAME);
    format(file,sizeof(file),"MyAdmin/Users/%s.txt",n);
    if(!dini_Exists(file)) return SendClientMessage(playerid,YELLOW,"You are not registered! Please /register");
    if(PInfo[playerid][Logged] == 1) return SendClientMessage(playerid,LIGHTBLUE,"You are already logged in!");
    if(PInfo[playerid][Regged] == 0) return SendClientMessage(playerid,ORANGE,"You are not registered! Please /register");
    if(strlen(params))
    {
You should already know what this does, if not, go back to the register command and read through it.
underneath that add:
pawn Код:
new pass[256];
        pass = dini_Get(file,"Password");
        if(dini_Exists(file))
        {
now we just created a variable to store the password in, we used dini_Get because password is a string, if it was an interval we would use dini_Int,
now we will have to check if the parameter which you enter matches up with the password in the file, so add:

pawn Код:
if(strcmp(params,pass,false) != 0)
            {
                SendClientMessage(playerid,YELLOW,"Wrong Password!");
            }
we used strcmp, strcmp is short for string compare, it is used when trying to compare 2 different strings, in this case the first string was the parameter of the login command, and the password, if it doesn't match it will send the error, "wrong password!", now we will create an else statement to show if the 2 strings do match, add underneath that:
pawn Код:
else
            {
                dini_IntSet(file,"Logged",1);
                PInfo[playerid][Logged] = 1;
                PInfo[playerid][Level] = dini_Int(file,"Level");
                SendClientMessage(playerid,YELLOW,"You have now logged in!");
                return 1;
            }
That will set the file so logged equals 1 (logged in) and the variable logged equals 1, it also sets our level to the level that was in the file, at this point the level should be 0 but we can change that.
Now we need a else statement again for the string length, add underneath that:

pawn Код:
}
    }
    else
    {
        SendClientMessage(playerid,GREY,"USAGE: /login <Password>");
        return 1;
    }
    return 1;
}
Congratulations, You have just created a perfectly working register and login system, why dont you compile it and go test it out .

Alright now its time to get started on a /setlevel command, this command will only be available for rcon users to use, but if you want you can change that, so go back to OnPlayerCommandText and add underneath all the other stuff,
pawn Код:
dcmd(setlevel,8,cmdtext);
BTW if you didn't already know when creating any command in dcmd you need to add one of these underneath OnPlayerCommandText, where 8 is the number of letters in the command.
Creating Your first admin command!
Go underneath the last command you made (login) and add this:
pawn Код:
dcmd_setlevel(playerid,params[])
{
    new level,id,file[256],n[MAX_PLAYER_NAME];//creating the new variabls
    new tmp[256], tmp2[256], Index,str[50];// creating the new variables
    tmp = strtok(params,Index), tmp2 = strtok(params,Index),id = strval(tmp),level = strval(tmp2);// setting them to strtok so we can use them as parameters of our command
    GetPlayerName(id,n,MAX_PLAYER_NAME);//getting the players name
    format(file,sizeof(file),"MyAdmin/Users/%s.txt",n);//formatting the file
now this is a big step up, but i will try to explain, the first 2 lines are variables to store stuff in like the name file etc
the tmp and tmp2 are like the add on bits of the command (/setlevel id level) when we created the string we made it only 50 cells big, because in a second I will show you the size of the string.
okay now underneath that we need to add in the strlen to make sure its not empty and also we need to make sure that the player is rcon admin so add:

pawn Код:
if(!IsPlayerAdmin(playerid)) return SendClientMessage(playerid,GREY,"You are not an RCON admin!");//if the player is not rcon admin
    if(!strlen(params)) return SendClientMessage(playerid,GREY,"USAGE: /setlevel <ID> <Level>");// if the string is empty
    if(!IsPlayerConnected(id))return SendClientMessage(playerid,GREY,"You have entered an incorrect ID"); //if the id is not connected
we also check to see if the id given is a connected player, now we need to actually set the file to the level, so add:
pawn Код:
PInfo[id][Level] = level;//sets the level of the player
    dini_IntSet(file,"Level",level);//saves the new level to the file
    format(str,sizeof(str),"You have set %s's level to %d",n,level);//creates the string
    SendClientMessage(playerid,LIGHTBLUE,str);
    return 1;
}
now your /setlevel command is complete! You can now play on your server and set levels to whatever you want
but that wont be any good if you cant /kick and /ban so lets get started on that:
Lets start with the kick command, if you have been paying attention you know that we need to add dcmd(kick,4,cmdtext); underneath OnPlayerCommandText so go ahead and do that, now underneath all the commands you have created add:
pawn Код:
dcmd_kick(playerid,params[])
{
    new id,n[MAX_PLAYER_NAME],on[MAX_PLAYER_NAME];
    new tmp[256], Index, str[49];
    tmp = strtok(params,Index), id = strval(tmp);
    GetPlayerName(id,on,sizeof(on));
    GetPlayerName(playerid,n,sizeof(n));
okay so these are all the variables which we will be using, tmp is defined as strtok it helps when making a space after the command, then we define id as strval(tmp), we then get teh names of the 2 people(you and the otherplayer your kicking) okay now add underneath that:
pawn Код:
if(PInfo[playerid][Level] < 3) return SendClientMessage(playerid,ORANGE,"You need to be level 3 to use this command!");
    if(!strlen(params)) return SendClientMessage(playerid,GREY,"USAGE: /kick <ID> ");
    if(!IsPlayerConnected(id)) return SendClientMessage(playerid,GREY,"Invalid ID");
    format(str,sizeof(str),"%s has kicked %s",n,on);
    SendClientMessageToAll(LIGHTBLUE,str);
    Kick(id);
    return 1;
}
that will check if the string is empty and the player is online then it will kick the player and send the string...

Now you have created your kick command, lets move onto the ban command

add underneath OnPlayerCommandext: dcmd(ban,3,cmdtext);
then add underneath all your other commands:
pawn Код:
dcmd_ban(playerid,params[])
{
    new id, n[MAX_PLAYER_NAME],on[MAX_PLAYER_NAME];
    new tmp[256], Index, str[49];
    tmp = strtok(params,Index), id = strval(tmp);
    GetPlayerName(id,on,sizeof(on));
    GetPlayerName(playerid,n,sizeof(n));
    if(PInfo[playerid][Level] < 3) return SendClientMessage(playerid,ORANGE,"You need to be level 3 to use this command!");
    if(!strlen(params)) return SendClientMessage(playerid,GREY,"USAGE: /ban <ID> ");
    if(!IsPlayerConnected(id)) return SendClientMessage(playerid,GREY,"Invalid ID");
    format(str,sizeof(str),"%s has banned %s",n,on);
    SendClientMessageToAll(ORANGE,str);
    Ban(id);
    return 1;
}
I wont explain it again everything in this command is the same as the /kick command except we use Ban(id); instead of Kick(id);

Well if you made it this far, give yourself a pat on the back, you now have a good working admin system which you can ban and kick players.

Finished Version!

From all that ive taught you, you should now know how to create some other commands, Ill give you some pointers:

/freeze - use TogglePlayerControllable 0
/unfreeze - TogglePlayerControllable 1
/explode - CreateExplosion
/goto - SetPlayerPos
/bring - SetPlayerPos
* PinkFloydLover slaps - SetPlayerHealth around a bit with a large trout.
/giveweapon - GivePlayerWeapon
/givemoney - GivePlayerMoney

Thats all for now, if you guys want me to I will make another tutorial relating to this called "Advancing your Admin Script", which will be an advancment of this!
Have Fun with this and also if you have any questions ask them!
Reply
#2

nice ) and useful
Reply
#3

Thanks!
Reply
#4

Simple to make but useful for newbies, nice tuto
Reply
#5

Great tutorial, very nicely explained, overall, good job!
Reply
#6

Nice Work. xD
Reply
#7

Thanks..khmm peoples like me need more tuts like this
Reply
#8

Thanks alot guys
Reply
#9

You got a problem, strtok is already defined.

EDIT: Its defined in the dini file.
Reply
#10

Okay thanks, I will update it...

This forum requires that you wait 120 seconds between posts. Please try again in 32 seconds.
Reply
#11

pawn Code:
}
    else
    {
        SendClientMessage(playerid,GREY,"USAGE: /register <Password>");
    }
    return 1;
}
return 1; after the sendclientmessage crashes server.
Reply
#12

nice tut it help me alot
Reply
#13

Who is still using Dini nowdays :S
Reply
#14

lots of people because they don't know how to learn MySQL

This forum requires that you wait 120 seconds between posts. Please try again in 48 seconds.
Reply
#15

Nice tut! One suggestion: use sscanf instead of strtok
Reply
#16

Great tutorial, really useful !
Reply
#17

Quote:
Originally Posted by willsuckformoney
View Post
pawn Code:
}
    else
    {
        SendClientMessage(playerid,GREY,"USAGE: /register <Password>");
    }
    return 1;
}
return 1; after the sendclientmessage crashes server.
It shouldn't crash your server but I geuss there is no reason for it to be there, I will edit it when I get time

Quote:
Originally Posted by H7_Tr0m
View Post
Nice tut! One suggestion: use sscanf instead of strtok
I was going to but I didn't want to have to many includes, I can do a tut with sscanf when I get time if anyone wants me to.

And thanks to everyone for the positive feedback
Reply
#18

btw I'm still working around with this too, helped me because I never had a start lol
Reply
#19

Thanks man, if you have any questions pm me
Reply
#20

good job , nice tutorial



Quote:

This forum requires that you wait 120 seconds between posts. Please try again in 48 seconds.

Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)