[Tutorial] Simplistic Admin saving/loading system using DOF2!
#1

Introduction

Well, hello, my name is OxigEN(aka Ox1gEN on sa-mp forums) and this is my first tutorial
on how to create a very simple saving/loading script.



Includes needed:

1)DOF2 - credits to Double-O-Seven
2)zcmd - credits to ZeeX
3)sscanf - credits to ******

Some defines to write faster and for colors:
#define SCM SendClientMessage
#define COLOR_RED 0xFF0000FF


Note before we start:

It is highly suggested to create a saving/loading login/registeration for this script
why? Because without it any player using the name of an admin name can log-in
and use the admin's permissions.



Alright then, let's start.

First you must download the includes:

DOF2
zcmd
&& sscanf2.

At the top of your script you must add this code:

Код:
#include <a_samp>
#include <DOF2>
#include <zcmd>
#include <sscanf2>
What this code does? well it bassicly includes the files to the script so we can actually do what
we want to do in a simpler, better and more efficient way.

Second, we need to create our enum and a variable:

Код:
enum pStats
{
       pAdmin
}

new pInfo[MAX_PLAYERS][pStats];
So, after we had done that, let me explain what it means:
we have created an enum(move information herefor information about it) and then we have
created a variable called pInfo[MAX_PLAYERS][pStats] so we bassicly "hold" the data in a variable,
MAX_PLAYERS means it's bassicly taking the number of online max players in the server and pStats
is bassicly the enumerator's name(enum's name).

Now let's work on our bassicly saving/loading system of the administration script
before we actually make commands about how to set someone's admin level, make him an
admin or even remove his admin completely and then save the file.


Before we move on to saving admins and loading them lets create a couple of simple stocks:

Код:
stock pFile(playerid)
{
	new pName[MAX_PLAYER_NAME +1];
	new File[50];
	GetPlayerName(playerid,pName,MAX_PLAYER_NAME);
	format(File,sizeof(File),"%s.ini",pName);
	return File;
}

stock LoadPstats(playerid)
{
    pInfo[playerid][pAdmin] = DOF2_GetInt(pFile(playerid), "AdminLevel");
}

stock GetName(playerid)
{
	new pName[MAX_PLAYER_NAME];
	
	GetPlayerName(playerid, pName, sizeof(pName));
	return pName;
}

stock GetName2(playerid)
{
	new pName2[MAX_PLAYER_NAME];
	
	GetPlayerName(playerid, pName2, sizeof(pName2));
	return pName2;
}
So in the first stock we find the user's path to save/load his stuff from there,
then in the second stock we load the player's stats on the server(it is useful if you are lazy
and/or don't want to write alot of stuff when player connects, etc.

the line in the second stock:
pInfo[playerid][pAdmin] = DOF2_GetInt(pFile(playerid), "AdminLevel");

Bassicly means that pInfo(name of the variable we created) [playerid] (because w
e used max_players) [pAdmin] (what we have in the enumerator) EQUALS (=) to DOF2_GetInt(pFile(playerid), "AdminLevel");

Why DOF2_GetInt? Because later on in this tutorial we set a player's integer that is
called "AdminLevel" to zero
IF he had never logged into the server, otherwise it'll instantly load the player's stats using the stock (LoadPstats(playerid).
The pFile(playerid) part bassicly finds the player's path and Gets(DOF2_GetInt) the Int(integer) from the
player's stats and sets them automaticly once a player that has been into the server already has connect.

Now for the third stock, GetName(playerid):

Here we bassicly get the player's name, the player that has done a certain comm
and, NOT THE PLAYER THAT THE COMMAND IS AFFECTING (I had to mark this because I myself get confused with it alot since I'm still a beginner) so if we'd like to format the
message and say to the ID that the command is affecting that admin %s has made you an admin,
it'll bassicly get the player's name,
the one who did the command and not the one who the command affects.

Now for the fourth and final stock, GetName2(id):

Bassicly you don't really need this if in a command/public or what ever you make a
variable called id and then use GetName(id) it'll work exactly the same
, but I like to use it like so it'll be arranged better, and look better in my eyes.



Okay, now that I had finished explaining all of the stocks lets move on the actual script.


First in the public function OnPlayerConnect(playerid) you need to do this:

Код:
public OnPlayerConnect(playerid)
{
	if(DOF2_FileExists(pFile(playerid)))
	{
	    SpawnPlayer(playerid);
	    LoadPstats(playerid);
	}
	else  //It is suggested to create a login/register system in order to keep people's player safe and no one could hack it (unless they have the password of course).
	{
	    DOF2_CreateFile(pFile(playerid));
	    DOF2_SetInt(pFile(playerid), "AdminLevel", 0);
	    DOF2_SaveFile();
	    SpawnPlayer(playerid);
	}
	return 1;
}
So here. We bassicly check if a certain file of the player exits using DOF2_FileExists(pFile(playerid)
this bassicly checks if the file of the player exists and it gets the name of the player so it can look
for the player's file.

After that we do SpawnPlayer(playerid), it bassicly spawns the player
and then we Load the player's stats using our stock! LoadPstats(playerid).

Now we have something called "else" it bassicly says that if this and this wasn't found or something else
then this should come up.
In our case It is suggested to create a registration system using DOF2 for this script but it depends
on for who you're creating the server for.

Okay, now bassicly the else checks if a player's file DOES NOT exist then it should bassicly
create a file for the player with the name of the player (DOF2_CreateFile(pFile(playerid) ) and then it sets an integer
in the player's file called "AdminLevel" and sets it to zero using DOF2_SetInt(pFile(playerid), "AdminLevel", 0);
and then it saves the file using DOF2_SaveFile();
NOTE, YOU MUST SAVE THE FILE OR ELSE THE PLAYER'S FILE WON'T SAVE...
and then we bassicly spawn the player using SpawnPlayer(playerid);
Then we bassicly return 1; and close the brackets.

After we've checked if the player's file exists or not and if it doesn't we create him a file we now need to add these
lines in the public: OnPlayerDisconnect(playerid, reason)
and for that we use this code:

Код:
public OnPlayerDisconnect(playerid, reason)
{
	DOF2_SetInt(pFile(playerid), "AdminLevel",pInfo[playerid][pAdmin]);
	DOF2_SaveFile();
	return 1;
}
Here, we bassicly set and integer in the player's file for admin level once he exited, and we get that integer from
the variable we created, how? When we set a player's admin level later on.
Then we save the file again because if we don't it won't load/save the player's stats.

BTW: if you have created more Integers for the players to save you can just add them into LoadPstats and onplayerconnect and disconnect, regularly.



Okay, now after we've managed to save/load the player's stats, etc, we can move on to actually setting a player's
admin level.
To do that we first need to create a CMD with zcmd.

So, let's create it then I'd explain how it works.

Код:
CMD:setadmin(playerid, params[])
{
	new id, string[128], levels;

	if(!IsPlayerAdmin(playerid)) return SCM(playerid, -1, "You're not an admin! Therefore you may not use this command"); //Admin RCON only.
        else if(sscanf(params, "ud", id, levels)) return SCM(playerid, -1, "USAGE: /setadmin [ID] [AdminLevel]");
        else if(id == INVALID_PLAYER_ID) return SCM(playerid, -1, "The id you've entered is either incorrect or invalid");
        else if(levels > 5) return SCM(playerid, COLOR_RED, "There are only FIVE availiable admin levels!");
	if(levels <= 5)
	{
	        format(string, sizeof(string), "Lead Admin %s(%d) has set your admin level %d. Congratulations!", GetName(playerid), playerid, levels);
		SCM(id, COLOR_RED, string);
		pInfo[id][pAdmin] = levels;
		DOF2_SetInt(pFile(id), "AdminLevel", levels);

		format(string, sizeof(string), "You have set %s(%d) admin level of %d.", GetName2(id), id, levels);
		SCM(playerid, COLOR_RED, string);
		DOF2_SaveFile();
	}
	return 1;
}
Okay, now let me explain some stuff.
First of all we have used a regular syntax of a zcmd command,
then we created acouple of variables.
And after that we started and checked if a player's connected to rcon admin using "if(!IsPlayerAdmin(playerid))"
the "!" bassicly means "NOT" if the player is NOT an admin then do this and this.
In this case if the player isn't an admin then it'd return a client message saying that you're not an admin, etc.

After the first party we use "else if" which bassicly means that if the player isn't an admin then don't do other stuff,
first check if the player isn't this or did that.
In the first "else if" we use sscanf to check if the player didn't write anything and then we use "ud", id, levels.
It bassicly means that "u" is a number in this case an ID and d which is a full number means that it is levels(admin levels.)
After that we return a message with the syntax or usage however you want to call it for the player, it bassicly tells
them how to use the command.
Then we create another else if to check if the ID we've entered equals to an INVALID_PLAYER_ID (I believe that
the number of an invalid player id is 60550 or something like that, not sure though.)
then we return a message saying that the id you've entered is either incorrect or invalid.

And then we are bassicly doing another "else if" (Yes, alot of else if's ) saying that if the number of levels that
we wrote is greater than 5(You can also do >= 5 which means if it's greater than OR equals to five)
then return a client message saying that there are only five available levels to choose from.

Now here we can do "else" but I did "if" to like check exactly if the levels we want to give are lower than or equal
to five.
And if they are then it should format a message saying that admin %s([with id of] %d) has given you %d admin levels!.
And then we bassicly define the admin's name(THE ONE WHO DID THE COMMAND) by using our stock:
GetName(playerid), and to get the playerid we simply use "playerid" then to get the levels we have inserted
and given to the player we do "levels" at the end, why?
Because there are three variables we need to define within the format.

After that we send the string to the player with the COLOR_RED.
And then we set the player's admin levels.

We first define the variable of pInfo[MAX_PLAYERS][pStats] of our enum and set it to "levels" the levels that
we have inserted by doing:

pInfo[id][pAdmin] = levels;
Why we use id here instead of playerid? Becase the command doesn't affect the one who did it(the player-id) it affects the ID the one who the command was used on.

Then we change and set the integer in DOF2 by using DOF2_SetInt(pFile(id), "AdminLevel, levels);
This is bassicly the same as the pInfo but this actually saves it and not defines it for the id.
Then we format the message for the player who has done the command telling him that you have set
%s([id of the player] %d) admin levels of %d. Then we define the variables of these % stuff to GetName2(id)
id, and levels, why GetName2(id)? So we can get the player's name that the command affects.
Then at the end like usually we Save the file in order for it to save(logic asfff) using DOF2_SaveFile();
Then we close the brackets and there you go, you've saved the player's admin level.

Now to remove a player's admin here's the code, IF YOU HAVE understood the first code on how to set someone's
admin level then you'd understand this:

Код:
CMD:removeadmin(playerid, params[])
{
	new id, string[128], reason[128];
	if(DOF2_GetInt(pFile(playerid), "AdminLevel") < 5) return SCM(playerid, -1, "You're not an admin! Therefore you may not use this command");
	else if(sscanf(params, "us[50]", id, reason)) return SCM(playerid, -1, "USAGE: /removeadmin [ID] [REASON]");
	else if(id == INVALID_PLAYER_ID) return SCM(playerid, -1, "The ID you've entered is either incorrect or invalid!");
	else if(pInfo[id][pAdmin] == 0) return SCM(playerid, COLOR_RED, "That player isn't an admin!");
	else
	{
	    format(string, sizeof(string), "Lead Admin %s(%d) has removed your admin level - Reason: %s", GetName(playerid), playerid, reason);
	    SCM(id, COLOR_RED, string);

	    format(string, sizeof(string), "You have removed %s(%d)'s administrator position! Reason: %s", GetName2(id), id, reason);
	    SCM(playerid, COLOR_RED, string);

	    pInfo[id][pAdmin] = 0;
	    DOF2_SetInt(pFile(id), "AdminLevel", 0);
	    DOF2_SaveFile();
	}
	return 1;
}
Just go to the /setadmin part if you didn't understand this, it's very simple if you understood the first part.

Now to make some commands using DOF2, zcmd and sscanf2!

First lets make a /kick command using those includes:

Код:
CMD:kick(playerid, params[])
{
	new id, reason[126], string[128];
	if(!DOF2_GetInt(pFile(playerid), "AdminLevel")) return SCM(playerid, -1, "You're not an admin! Therefore you may not use this command");
	else if(sscanf(params, "us[50]", id, reason)) return SCM(playerid, -1, "USAGE: /kick [ID] [REASON]");
	else if(id == INVALID_PLAYER_ID) return SCM(playerid, -1, "The id you've entered is either incorrect or invalid");
	else
	{
		format(string, sizeof(string), "[KICK]: %s(%d) has been kicked by %s(%d) - Reason: %s", GetName2(id), id, GetName(playerid), playerid, reason);
		SendClientMessageToAll(COLOR_RED, string);
		Kick(id);
	}
	return 1;
}
This code is bassicly self explanatory why? Because I've already explained it up in the tutorial. But the part I didn't is
this "if(!DOF2_GetInt(pFile(playerid), "AdminLevel")) return SCM........"
Now the sscanf checks if you wrote nothing plus if you're using sscanf2 then you must add a string length(in this case [50]).
This bassicly means that once a player does the command it checks if a player has the correct levels needed, in this
case we use "!" because it says "NOT" and if it says "NOT" then even a player with level one admin can kick, but
a player with level zero couldn't.

NOTE IF YOU'D LIKE TO CREATE A COMMAND FOR A CERTAIN ADMIN LEVE DO THIS:

Instead of the "if(!DOF2_GetInt(pFile(playerid), "AdminLevel")) return SCM........" do this:

"if(DOF2_GetInt(pFile(playerid), "AdminLevel") < 2) return SCM(playerid, COLOR_RED, "You don't have permission
to do this command!");


And that's bassicly it!



I hope I helped any of you guys who didn't know how to make it or something, because for me it took some time
to know how to make one of these.

Once you get the hang of this you can start making permissions for other stuff, for example a police system or something
it all depends on you.


Now final thing!:
Add this into your script:

Код:
public OnGameModeExit()
{
	DOF2_SaveFile(); /* Here you must DOF2_SaveFile(); in order to save the file */
	DOF2_Exit(); /* Here you must DOF2_Exit(); in order to close DOF2 */
}
This again saves the file and then closes and exits DOF2 once you close the server!


Paste Bin: http://pastebin.com/cAxt8s0z


Credits:

Ox1gEN (me)
DOF2 - Double-O-Seven
zcmd - ZeeX
sscanf2 - ******
First comment/topic
Reply
#2

In which era you live?
Reply
#3

Quote:
Originally Posted by LivingLikeYouDo
Посмотреть сообщение
In which era you live?
lol, you made me laugh right there.

In which era do I live, why do you ask that?
DOF2 isn't ancient and it's a great files library, I don't see the problem here.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)