14.04.2015, 19:13
Introduction
y_groups is an integral part of many YSI libraries (y_classes, y_commands etc) which provides a single implementation for any grouping of players you may like. Examples of "groups" of players include admin levels, factions, gangs and teams. A collection of people with the same options is a "group", and people can be in multiple "groups" - an admin on a role-play server may still be in a faction for role-playing in-character.
For this article we will develop a very simple script which can add and remove admin commands in one line (so you can make ANY command admin or not).
Librariers and Commands
y_groups can interact with any library with the right interface (making it completely optional). This interface is an article for another time, but y_commands provides this interface (basically it has per-player permissions which can be set and unset by y_groups). First lets create a basic mode with all required libraries and three commands:
Now those commands are VERY basic, but they're just for show. Currently any player can use those commands, even the "/ban" command - this is not a good idea.
y_groups
y_groups has a very flexible API - it is actually defined in terms of other libraries. In this can the functions available include:
Permissions
Admin levels using y_groups can be done in two ways. The first is to have every level as a separate group and set all permissions for every level. The second is instead of having groups: "level 1", "level 2" etc, you have groups: "level 1+", "level 2+" etc. With "levels", people in level 2 can use level 1 commands, so they are level 1 admins AND level 2 admins. Lets generically create a number of admin levels:
So we now have three admin levels, we need to set commands to be used only by admins. This is an implementation of the first method of making admin levels (by far the simplest):
You can now load and change admin levels in one place. Updating commands does not require modifying the command in any way - you could even set command permissions in a file or database for dynamic permissions.
In addition, you may have a command which can be used by admins of level 2 AND people in the "police" faction (let's call this command "arrest"):
Note that "SetAdminCommand" contains a call to "Group_SetGlobalCommand" which prevents people using the command by default. If this was not an admin command but a faction command that call would still be needed.
Players
The one thing missing from the code above is a way to actually add people to a group, fortunately this is easily done with "Group_SetPlayer":
Interestingly, the function "Group_SetPlayer" actually meets part of the requirements of a library to support groups, so you could in theory have groups which are part of other groups - this would be a third way of doing admin commands by simply adding the level 1 admin group to the level 2 admin group.
Other Functions
There are a few other functions available for use. Remember that "Command" can be replaced with "Class" or any other identifier for a library using y_groups:
Iterators
y_groups is foreach compatible:
That will loop through all the players in the "gPolice" group.
That will loop through all the groups that a player is in. Note that foreach was updated a few weeks/months ago to support exactly this because this uses a "Group:" tag.
GROUP_ADD
If you are making a large number of objects (for example), then manually setting the group for every one of them can be tedious. To cover the common case where you want a set of elements in just ONE group (not the global group), there is now a "GROUP_ADD" macro:
That will create a line of bins near the centre of the world that ONLY people in group "Admin 1" can see. Note that any objects (or anything else for that matter) created AFTER the "GROUP_ADD" block will have whatever you previously set the default permissions. For reference, the "default default" permissions are that everything is in the "global" group and no other group.
Note that this example used functions from the streamer plugin, which are now supported by y_groups.
Now obviously you can't create commands in this way, because commands already exist in the mode at compile time and are set up automatically by the system. However, you can still "touch" the commands inside the "GROUP_ADD" block to entirely reset their permissions to just the specified group:
Using that code, only people in the "myAdminGroup" group will be able to use the commands "help" and "commands". I've frequently tried to think of some way of doing this:
Such that that command only exists for a group called "gg", but as of yet I've not managed it. However, that has given me another idea.
Credits
This post was originally written by Y_Less. I'm merely reposting it for future scripters to develop their knowledge.
y_groups is an integral part of many YSI libraries (y_classes, y_commands etc) which provides a single implementation for any grouping of players you may like. Examples of "groups" of players include admin levels, factions, gangs and teams. A collection of people with the same options is a "group", and people can be in multiple "groups" - an admin on a role-play server may still be in a faction for role-playing in-character.
For this article we will develop a very simple script which can add and remove admin commands in one line (so you can make ANY command admin or not).
Librariers and Commands
y_groups can interact with any library with the right interface (making it completely optional). This interface is an article for another time, but y_commands provides this interface (basically it has per-player permissions which can be set and unset by y_groups). First lets create a basic mode with all required libraries and three commands:
Code:
#include <YSI\y_commands> #include <YSI\y_groups> #include <sscanf2> YCMD:kick(playerid, params[], help) { if (help) { return SendClientMessage(playerid, 0xFF0000AA, "Kicks another player."); } else { new pid, reason[32]; if (sscanf(params, "uS[32]", pid, reason)) { return SendClientMessage(playerid, 0xFF0000AA, "Parameters: <playerid/name> [reason]"); } if (reason[0]) { SendClientMessage(pid, 0xFF0000AA, "You have been kicked. Reason:"); SendClientMessage(pid, 0xFF0000AA, reason); } else { SendClientMessage(pid, 0xFF0000AA, "You have been kicked."); } Kick(pid); } return 1; } YCMD:ban(playerid, params[], help) { if (help) { return SendClientMessage(playerid, 0xFF0000AA, "Bans another player."); } else { new pid, reason[32]; if (sscanf(params, "uS[32]", pid, reason)) { return SendClientMessage(playerid, 0xFF0000AA, "Parameters: <playerid/name> [reason]"); } if (reason[0]) { SendClientMessage(pid, 0xFF0000AA, "You have been banned. Reason:"); SendClientMessage(pid, 0xFF0000AA, reason); } else { SendClientMessage(pid, 0xFF0000AA, "You have been banned."); } Ban(pid); } return 1; } YCMD:pm(playerid, params[], help) { if (help) { return SendClientMessage(playerid, 0xFF0000AA, "Sends a private message to another player."); } else { new pid, message[32]; if (sscanf(params, "us[32]", pid, message)) { return SendClientMessage(playerid, 0xFF0000AA, "Parameters: <playerid/name> <message>"); } SendClientMessage(pid, 0xFF0000AA, "Incoming message:"); SendClientMessage(pid, 0xFF0000AA, message); SendClientMessage(playerid, 0xFF0000AA, "Sent!"); } return 1; } main() { }
y_groups
y_groups has a very flexible API - it is actually defined in terms of other libraries. In this can the functions available include:
- Code:
Group:Group_Create(name[]);
- Code:
Group_SetCommand(Group:group, command, bool:set);
- Code:
Group_SetGlobalCommand(command, bool:set);
Permissions
Admin levels using y_groups can be done in two ways. The first is to have every level as a separate group and set all permissions for every level. The second is instead of having groups: "level 1", "level 2" etc, you have groups: "level 1+", "level 2+" etc. With "levels", people in level 2 can use level 1 commands, so they are level 1 admins AND level 2 admins. Lets generically create a number of admin levels:
Code:
// Up to 99. #define MAX_ADMIN_LEVELS (3) new Group:gAdmins[MAX_ADMIN_LEVELS]; public OnGameModeInit() { new name[16]; for (new i = 0; i != MAX_ADMIN_LEVELS; ++i) { format(name, sizeof (name), "Admin Level %d+", i + 1); gAdmins[i] = Group_Create(name); } }
Code:
SetAdminCommand(command[], level) { // Get the ID of the command (required): new id = Command_GetID(command); if (level) { // To be used only by admins. // First let no normal people use it. Group_SetGlobalCommand(id, false); // Then loop through admin levels and set it true on the ones it can be // used by and false on the others. new cl = 0; while (cl != MAX_ADMIN_LEVELS) { new Group:group = gAdmins[cl]; ++cl; if (cl == level) { // Set this level as using the command. Group_SetCommand(group, id, true); } else { // Set this level as not using this command. Group_SetCommand(group, id, false); } } } else { // To be used by everyone, so let everyone use it. Group_SetGlobalCommand(id, true); } }
Code:
public OnGameModeInit() { // As before. new name[16]; for (new i = 0; i != MAX_ADMIN_LEVELS; ++i) { format(name, sizeof (name), "Admin Level %d+", i + 1); gAdmins[i] = Group_Create(name); } // New. // "/kick" is a level 1 admin command. SetAdminCommand("kick", 1); // "/ban" is a level 2 admin command. SetAdminCommand("ban", 2); // "/pm" is not an admin command (not required as it's the default). SetAdminCommand("pm", 0); }
Code:
new Group:gPolice; public OnGameModeInit() { // As before. new name[16]; for (new i = 0; i != MAX_ADMIN_LEVELS; ++i) { format(name, sizeof (name), "Admin Level %d+", i + 1); gAdmins[i] = Group_Create(name); } SetAdminCommand("kick", 1); SetAdminCommand("ban", 2); SetAdminCommand("pm", 0); // New. gPolice = Group_Create("Police faction"); SetAdminCommand("arrest", 2); Group_SetCommand(gPolice, Command_GetID("arrest"), true); }
Players
The one thing missing from the code above is a way to actually add people to a group, fortunately this is easily done with "Group_SetPlayer":
Code:
public OnPlayerConnect(playerid) { if (IsPlayerAdmin(playerid)) { // Add the player to the second admin level. Default is not a member. Group_SetPlayer(gAdmins[2], playerid, true); // "false" is used to remove a player. } }
Other Functions
There are a few other functions available for use. Remember that "Command" can be replaced with "Class" or any other identifier for a library using y_groups:
- Code:
Group:Group_Destroy(Group:group);
- Code:
Group_SetCommandDefault(Group:group, bool:set);
- Code:
Group_SetGlobalCommandDefault(bool:set);
- Code:
bool:Group_GetPlayer(Group:group, playerid);
- Code:
Group_SetName(Group:group, name[]);
Code:Group_GetName(Group:group);
Iterators
y_groups is foreach compatible:
Code:
foreach (new playerid : Group(gPolice)) { }
Code:
foreach (new Group:group : PlayerGroups(playerid)) { }
GROUP_ADD
If you are making a large number of objects (for example), then manually setting the group for every one of them can be tedious. To cover the common case where you want a set of elements in just ONE group (not the global group), there is now a "GROUP_ADD" macro:
PHP Code:
new
Group:g = Group_Create("Admin 1");
GROUP_ADD<g>
{
CreateDynamicObject(1337, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0);
CreateDynamicObject(1337, 1.0, 0.0, 4.0, 0.0, 0.0, 0.0);
CreateDynamicObject(1337, 2.0, 0.0, 4.0, 0.0, 0.0, 0.0);
CreateDynamicObject(1337, 3.0, 0.0, 4.0, 0.0, 0.0, 0.0);
CreateDynamicObject(1337, 4.0, 0.0, 4.0, 0.0, 0.0, 0.0);
CreateDynamicObject(1337, 5.0, 0.0, 4.0, 0.0, 0.0, 0.0);
}
Note that this example used functions from the streamer plugin, which are now supported by y_groups.
Now obviously you can't create commands in this way, because commands already exist in the mode at compile time and are set up automatically by the system. However, you can still "touch" the commands inside the "GROUP_ADD" block to entirely reset their permissions to just the specified group:
PHP Code:
GROUP_ADD(myAdminGroup)
{
@YCMD:help;
@YCMD:commands;
}
PHP Code:
YCMD:help<gg>(playerid, params[], help)
{
}
Credits
This post was originally written by Y_Less. I'm merely reposting it for future scripters to develop their knowledge.