Admin system for beginners -
Eoussama - 04.10.2016
Howdy,
So a lot of people were requesting this on this forums, on social medias, even on ******* comments, So I thought that here I should step forward and tutor others who aren't aware of such technics to do certain things,
so hope you guys enjoy...
REQUIREMENTS
the last version of sscanf,
http://download2124.mediafire.com/h2...00-dneeTHA.rar
ZCMD :
https://sampforum.blast.hk/showthread.php?tid=91354
YSI\y_ini :
http://forum.sa-mp.com/showthread.ph...957(Pa%C4%8Dio
TUTORIAL
So first of all, you must include the new installed files, they should go beneath the a_samp include,
Код:
#include <a_samp>
#include <ZCMD>
#include <sscanf2>
#include <YSI\y_ini>
now, if we are going to do this, let's make it perfect, we want to make the admin status auto acquired by admins when logging-in, thus we must save the data somewhere, so let's define the path of the data saving,
Код:
#define ADMIN_PATH "/Admins/%s.ini"
Ok, now we want to rename the data-holding file to the player's name, to do so, insert the following code,
Код:
AdminPath(playerid) {
new
str[36],
name[MAX_PLAYER_NAME];
GetPlayerName(playerid, name, sizeof(name));
format(str, sizeof(str), ADMIN_PATH, name);
return str;
}
you might have a palm face now, and say, wait..w.wwhat? Wth just happened, well, just chill mate, and let me start explaining what the code above stands for,
so as you can see, we created a string named "str" and set it's size to 36, and the other variable to hold the player's name which is "name" and its size is MAX_PLAYER_NAME, which is by default equal to 24,
after that, we stored the player's name in the variable "name", then comes the "format", which replaces the file's name with the player's name, so that we will final have a .ini file with the player's name,
let's move on.
Now we need to declare new variables, so let's got ahead and use the enum function
Код:
enum E_ADMIN_DATA {
AdminLevel,
bool:LoggedIn
}
so we've created the "AdminLevel" variable and the "LoggedIn" boolean, which is by default set to false,
underneath of that, do this:
Код:
new PlayerInfo[MAX_PLAYER_NAME][E_ADMIN_DATA];
OK, now he are done with the first part, make sure that your script look like this :
Код:
#include <a_samp>
#include <ZCMD>
#include <sscanf2>
#include <YSI\y_ini>
#define ADMIN_PATH "/Admins/%s.ini"
AdminPath(playerid) {
new
str[36],
name[MAX_PLAYER_NAME];
GetPlayerName(playerid, name, sizeof(name));
format(str, sizeof(str), ADMIN_PATH, name);
return str;
}
enum E_ADMIN_DATA {
AdminLevel,
bool:LoggedIn
}
new PlayerInfo[MAX_PLAYER_NAME][E_ADMIN_DATA];
before you do anything, go to "scriptfiles" and create a new folder, thennamed it "Admins"
now, moving the second part, go to the OnPlayerConnect(playerid) callback, and type this:
Код:
PlayerInfo[playerid][AdminLevel] = 0;
PlayerInfo[playerid][LoggedIn] = false;
what the first line means is, when a player their stats would be reseted concerning their AdminLevel until their identify get confirmed, (world perfectly with a login system),
right underneath that, insiter the following,
Код:
GetPlayerName(playerid, name, sizeof(name));
if(fexist(AdminPath(playerid))) {
INI_ParseFile(AdminPath(playerid), "LoadPlayerData_AdminData", .bExtra = true, .extra = playerid);
}
so this part should look like this:
Код:
public OnPlayerConnect(playerid)
{
PlayerInfo[playerid][AdminLevel] = 0;
PlayerInfo[playerid][LoggedIn] = false;
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid, name, sizeof(name));
if(fexist(AdminPath(playerid))) {
INI_ParseFile(AdminPath(playerid), "LoadPlayerData_AdminData", .bExtra = true, .extra = playerid);
}
return 1;
}
that part was all about reseting the player's stats and checking if they previousely have an admin data file,
the INI_ParseFile function is calling a forwarded callback, which we are about to creat,
next, go ahead bellow thes OnPlayerConnect callback and forward,
Код:
Код:
forward LoadPlayerData_AdminData(playerid, name[], value[]);
now right below this, type the following code,
Код:
public LoadPlayerData_AdminData(playerid, name[], value[]) {
INI_Int("AdminLevel", PlayerInfo[playerid][AdminLevel]);
return 1;
}
that callback above stands for making the admin level data stored in form of an integer, that's why we had in the biggining INI_
Int
OK, now we made the necessary part, let's do the setlevel command next,
this is going to work for both level 4 admins and rcon admins, therefore the code should look like this,
Код:
CMD:setlevel(playerid, params[]) {
if(IsPlayerAdmin(playerid) || PlayerInfo[playerid][AdminLevel] >= 3)
{
//do something here
return 1;
else {
SendClientMessage(playerid, 0xFF0000, "[ERROR]: you are not authorized to use this command");
return 1;
}
}
next define some variables,
Код:
CMD:setlevel(playerid, params[]) {
if(IsPlayerAdmin(playerid) || PlayerInfo[playerid][AdminLevel] >= 3)
{
new
string[MAX_PLAYER_NAME+64],
pname[MAX_PLAYER_NAME],
tname[MAX_PLAYER_NAME],
targetid,
level;
//do something here
return 1;
else {
SendClientMessage(playerid, 0xFF0000, "[ERROR]: you are not authorized to use this command");
return 1;
}
}
string[MAX_PLAYER_NAME+64] : a string which is going to be used to display a message, its size is ([MAX_PLAYER_NAME] = 24)+64 which is 88
pname[MAX_PLAYER_NAME] : a variable which will hold the player's name (the admin who is using the command), its size is 24
tname[MAX_PLAYER_NAME] : a variable that holds the target id's name (the player whom is going to be promoted/demoted), its size is 24
targetid : self-explanatory, a variable which helps define the target's id,
level : this will hold the value of the admin level you want to stick to someone,
next step, we are goin to tell the server what to do in case a player uses the command with null parameters, and where comes sscanf's role, so type this in your code
Код:
if(sscanf(params, "ii", targetid, level))
{
return SendClientMessage(playerid, -1, "USAGE: /setlevel (playerid) (level)");
}
then your code should look like this:
Код:
CMD:setlevel(playerid, params[]) {
if(IsPlayerAdmin(playerid) || PlayerInfo[playerid][AdminLevel] >= 3)
{
new
string[MAX_PLAYER_NAME+64],
pname[MAX_PLAYER_NAME],
tname[MAX_PLAYER_NAME],
targetid,
level;
if(sscanf(params, "ii", targetid, level))
{
return SendClientMessage(playerid, -1, "USAGE: /setlevel (playerid) (level)");
}
//do something here
return 1;
else {
SendClientMessage(playerid, 0xFF0000, "[ERROR]: you are not authorized to use this command");
return 1;
}
}
what we've done so far, is sending a client message to the user "USAGE:..etc" in case he didn't add the command params,
so next, we need to check if the targetid(the promoted/demoted guy) is connected or has a valid ID,
in order to do this, we need to loop through all connected players one by one, and the fast way to do this is using "for" statement, so we need to add this,
Код:
for(new i=0;i<MAX_PLAYERS; i++) continue; {
if((!IsPlayerConnected(targetid)) || (targetid == INVALID_PLAYER_ID))
{
SendClientMessage(playerid, 0xFF0000, "Player Is Not Connected!");
}
}
if(level < 1 || level > 4)
{
return SendClientMessage( playerid, 0xFF0000, "available levels (1-4)");
}
OK, let's freez a minute and explain the content above,
so first we started the code line with
for, which stands for a
loop, and what loop besically is? a loop is a sequence of instruction s that is continually repeated until a certain condition is reached, in this case, the targetid, so we typed
new i = 0, whioch creates a new variable "i" and sets its value to 0, then we typed
i<MAX_PLAYERS, which sets the limite of "i" to the max players connected, so now the value of "i"is closed between 0 and MAX_PLAYERS, next we typed,
i++, which tells the server to add 1 to the value of "i" every time, then we finished the line with
continue, your code will stop and start again at the start of the loop, skipping everything else after the
continue;
then we made a limite to admin levels, (1-4),
once you do all of this, your code should look like this:
Код:
CMD:setlevel(playerid, params[])
{
if((IsPlayerAdmin(playerid)) || PlayerInfo[playerid][AdminLevel] >= 3)
{
new
string[MAX_PLAYER_NAME+64],
pname[MAX_PLAYER_NAME],
tname[MAX_PLAYER_NAME],
targetid,
level;
if(sscanf(params, "ii", targetid, level))
{
return SendClientMessage(playerid, -1, "USAGE: /setlevel (playerid) (level)");
}
for(new i=0;i<MAX_PLAYERS; i++) continue; {
if((!IsPlayerConnected(targetid)) || (targetid == INVALID_PLAYER_ID))
{
SendClientMessage(playerid, 0xFF0000, "Player Is Not Connected!");
}
}
if(level < 1 || level > 4)
{
return SendClientMessage( playerid, 0xFF0000, "available levels (1-4)");
}
}
else
{
SendClientMessage( playerid, 0xFF0000, "you can't use this command!");
return 1;
}
return 1;
}
and now let's sent the players admin level,
first, let's store the player and target's names in their variables,
Код:
GetPlayerName(playerid, pname, sizeof(pname));
GetPlayerName(targetid, tname, sizeof(tname));
then send a client message to all, so players would notice the promotion,
Код:
format(string, sizeof(string), "Administrator %s has promoted %s to level %i admin", pname, tname, level);
SendClientMessageToAll(-1, string);
now to set the player's level, just type this
Код:
PlayerInfo[targetid][AdminLevel] = level;
we still missing the most important part, which is saving the data, do to so, we're going to use YSI\y_ini,
Код:
new INI:File = INI_Open(AdminPath(targetid));
INI_SetTag(File, "AdminData");
INI_WriteInt(File, "AdminLevel", PlayerInfo[targetid][AdminLevel]);
INI_Close(File);
so far, your overall command code, should look like this,
Код:
CMD:setlevel(playerid, params[])
{
if((IsPlayerAdmin(playerid)) || PlayerInfo[playerid][AdminLevel] >= 3)
{
new
string[MAX_PLAYER_NAME+64],
pname[MAX_PLAYER_NAME],
tname[MAX_PLAYER_NAME],
targetid,
level;
if(sscanf(params, "ii", targetid, level))
{
return SendClientMessage(playerid, -1, "USAGE: /setlevel (playerid) (level)");
}
for(new i=0;i<MAX_PLAYERS; i++) continue; {
if((!IsPlayerConnected(targetid)) || (targetid == INVALID_PLAYER_ID))
{
SendClientMessage(playerid, 0xFF0000, "Player Is Not Connected!");
}
}
if(level < 1 || level > 4)
{
return SendClientMessage( playerid, 0xFF0000, "available levels (1-4)");
}
else
{
GetPlayerName(playerid, pname, sizeof(pname));
GetPlayerName(targetid, tname, sizeof(tname));
format(string, sizeof(string), "Administrator %s has promoted %s to level %i admin", pname, tname, level);
SendClientMessageToAll(-1, string);
PlayerInfo[targetid][AdminLevel] = level;
new INI:File = INI_Open(AdminPath(targetid));
INI_SetTag(File, "AdminData");
INI_WriteInt(File, "AdminLevel", PlayerInfo[targetid][AdminLevel]);
INI_Close(File);
return 1;
}
}
else
{
SendClientMessage( playerid, 0xFF0000, "you can't use this command!");
return 1;
}
return 1;
}
all the data would be saved in "
scriptfiles > Admins"
hope I helped most of you guys,
if you find this useful, give it a +REQ
regards, oussama
Re: Admin system for beginners -
Spmn - 04.10.2016
Y u do dis?
Код:
for(new i=0;i<MAX_PLAYERS; i++) continue; {
if((!IsPlayerConnected(targetid)) || (targetid == INVALID_PLAYER_ID))
{
SendClientMessage(playerid, 0xFF0000, "Player Is Not Connected!");
}
}
Re: Admin system for beginners -
Eoussama - 04.10.2016
Quote:
Originally Posted by Spmn
Y u do dis?
Код:
for(new i=0;i<MAX_PLAYERS; i++) continue; {
if((!IsPlayerConnected(targetid)) || (targetid == INVALID_PLAYER_ID))
{
SendClientMessage(playerid, 0xFF0000, "Player Is Not Connected!");
}
}
|
when I don't add this, the server doesn't check if the targetid is valid or not,whatever the id you would enter, you would ended up being the targetid instead, even if you do /setlevel 5000 4 it would work
Re: Admin system for beginners -
GoldenLion - 04.10.2016
What about just
Код:
if (targetid == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "The specified player is not connected.");
It will do all the job...
Re: Admin system for beginners -
Luis- - 04.10.2016
Why are people still using ini? It's so outdated.
Re: Admin system for beginners -
Eoussama - 04.10.2016
Quote:
Originally Posted by Luis-
Why are people still using ini? It's so outdated.
|
what do you suggest
Quote:
Originally Posted by GoldenLion
What about just
Код:
if (targetid == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "The specified player is not connected.");
It will do all the job...
|
I tried it, the command always end up not working as it should, I would enter any ID and the cmd would still work but only on the playerid
Re: Admin system for beginners -
Luis- - 04.10.2016
MySQL is much easier than having to mess around with files.
Re: Admin system for beginners -
Eoussama - 04.10.2016
Quote:
Originally Posted by Luis-
MySQL is much easier than having to mess around with files.
|
can you give me links to some nice tutorials on MySQL? I want to learn it so bad
Re: Admin system for beginners - Quinncell - 04.10.2016
Quote:
Originally Posted by Luis-
Why are people still using ini? It's so outdated.
|
Most people start off with Y_ini even though I agree it's outdated but it's good for beginners.Imagine what the 'Script Help' section would be if everyone started off with MySQL xD
Quote:
Originally Posted by Eoussama
can you give me links to some nice tutorials on MySQL? I want to learn it so bad
|
Here you go >
https://sampforum.blast.hk/showthread.php?tid=129183
OT: The tutorial is quite useful for beginners.Well done.
Also, use the 'php' tags when making tutorials, it's much better imo.
Re: Admin system for beginners -
J0sh... - 04.10.2016
OH MY GOD SO MANY WRONG THINGS:
1ST:
Why are you looping to check if the player is connected? if(!IsPlayerConnected(targetid)) !!!!
2ND:
Why are you using 'i' for targetid, use 'u' sscanf supports name/id with 'u'. (IF U DOESNT WORK UPDATE IT)
Quote:
Originally Posted by KeithCooper
OT: The tutorial is quite useful for beginners.Well done.
|
WHAT??!!?!?!?! Sure, the INI parts are useful but no beginner should be seeing loops to check if a player is connected. Reminds me of people that don't even download a gm and say "Good job +rep"
Re: Admin system for beginners -
Gorgeousmaniac - 05.10.2016
Quote:
Originally Posted by Luis-
MySQL is much easier than having to mess around with files.
|
Well MySQL are for pros and low pros, I think that this tutorial is obviously made for beginners who don't know shts about things like MySQL databases.
Re: Admin system for beginners - Quinncell - 05.10.2016
@Jamester, you only named two wrong things that he done.Others criticized him above so me doing the same thing would be useless, don't you think?
Re: Admin system for beginners -
J0sh... - 05.10.2016
Quote:
Originally Posted by KeithCooper
@Jamester, you only named two wrong things that he done.Others criticized him above so me doing the same thing would be useless, don't you think?
|
Two MAJOR things. Nope, you spouting useless crap like good job! Sure, parts of it are alright! But the code inside those commands give me the shudders.
Re: Admin system for beginners -
AndySedeyn - 05.10.2016
Teaching new programmers terrible ways to do something is terrible on its own. I may sound like a hypocrite since I made a Y_INI tutorial, but I never claimed it was for new programmers. Moreover, I still use .ini for other purposes and not necessarily to excessively read and write data which is
not what it should be used for, btw.
And I don't know what your intentions were when you wrote this for-loop:
PHP Code:
for(new i=0;i<MAX_PLAYERS; i++) continue;
If you compile that, it will give you an error saying 'i' is undefined throughout the loop's body, because you're stopping the loop right after 'continue'. It will just loop from 0 to MAX_PLAYERS-1 without doing anything.
Re: Admin system for beginners -
Stinged - 06.10.2016
Quote:
Originally Posted by Eoussama
what do you suggest
I tried it, the command always end up not working as it should, I would enter any ID and the cmd would still work but only on the playerid
|
The reason why it's not working is because "i" is an integer specifier, so it never returns INVALID_PLAYER_ID, so you'll have to use IsPlayerConnected(targetid), but if you change it to "u", INVALID_PLAYER_ID is returned, so it should work.