I feel there is a more simple way to this, this seem excessive
CC @ltsmrsky
The way @officialnabalt wrote it is one way to go about it, but instead of seperate tables for each rank I would just put it all together in one table (Don’t mind the blurred bits):
After this, I would convert each rank into a number (Ex: Tester rank is 1, Admin is 2, etc)
The way I check the rank is a bit complicated, cause I’m not requiring the module on the client directly, but instead I’m using a remote function to get the rank on the server (To prevent spoofing, considering this is an admin system)
i suck at programming my bad man
Can you give me some code? Can’t really do much without any sample code
Client Script Example:
local Remote = game.ReplicatedStorage.RemoteFunction
local Rank = Remote:InvokeServer() -- Get the player's rank
if Rank <= 0 then
Cmdr:SetEnabled(false)
end
Server Script Example:
local Remote = game.ReplicatedStorage.RemoteFunction
local Ranks = require(script.Ranks)
Remote.OnServerInvoke = function(Player)
return Ranks:CheckRank(Player) -- Make a check rank function and return the result
end
Here’s an example. I am not giving out the code I use to check a player’s rank, but this should suffice.
A rank system really isn’t that hard, I hate to say it but if you aren’t really experienced with luau I wouldn’t recommend using this module. This system doesn’t give you a lot of commands out of the box as its designed for you to make your own commands tailored towards your game.
The docs for this system are more than helpful and I’d highly recommend taking a look into them. Particularly this one - Registry | Cmdr
Sorry it was 10pm for me and I regret making that post, but thanks for your contribution
Actually, do you know a way to be able to punish offline players? I need this for our muting system. I’ve checked the docs but I haven’t found anything; and I can’t use playerid because my muting system uses player names. Unless I forked it a lot which would take a while
Add a separate parameter to run the command using user ID by using the Cmdr data type for numbers or you could modify your code to write to a datastore for the next time the player joins by getting the players user ID by their username.
Moving this to DMs because this contains slightly private information
I’ve got this system to unban players, why won’t it work? The for players loop just won’t run.
Client:
return {
Name = "unban";
Description = "Unbans a player or a group of players";
Group = "Moderator";
Args = {
{
Type = "playerIds";
Name = "players";
Description = "The players to unban - Use player ids";
},
};
}
Server:
local Players = game:GetService("Players")
return function (context, players)
for _, player in pairs(players) do
Players:UnbanAsync(player.UserId)
end
return("Unbanned %d players."):format(#players)
end
Can anyone help me?
Looking into the Types it seems like playerIds only returns for users inside the server.
As this is an unbanning script it’s highly unlikely that the user your unbanning is going to be inside the server so there is a few things you’d need to modify within the Cmdr Types.
Inside your Cmdr > Types folder you should see the module called “PlayerId”, update the source code of that module with what’s below, this will allow for a mixture of users in-game and users not in-game to be added to the list.
What was happening before is the ID you were trying to unban wasn’t in the server so it wasn’t adding them to the list.
local Util = require(script.Parent.Parent.Shared.Util)
local Players = game:GetService("Players")
local nameCache = {}
local function getUserId(name)
if nameCache[name] then
return nameCache[name]
elseif Players:FindFirstChild(name) then
nameCache[name] = Players[name].UserId
return Players[name].UserId
else
local fetchedName, username = pcall(Players.GetNameFromUserIdAsync, Players, name)
local fetchedUserId, userid = pcall(Players.GetUserIdFromNameAsync, Players, username)
if userid ~= tonumber(name) then
return nil
end
nameCache[username] = userid
return userid
end
end
local playerIdType = {
DisplayName = "Full Player Name";
Prefixes = "# integer";
Transform = function (text)
local findPlayer = Util.MakeFuzzyFinder(Players:GetPlayers())
return text, findPlayer(text)
end;
ValidateOnce = function (text)
return getUserId(text) ~= nil, "No player with that name could be found."
end;
Autocomplete = function (_, players)
return Util.GetNames(players)
end;
Parse = function (text)
return getUserId(text)
end;
Default = function(player)
return player.Name
end;
}
return function (cmdr)
cmdr:RegisterType("playerId", playerIdType)
cmdr:RegisterType("playerIds", Util.MakeListableType(playerIdType, {
Prefixes = "# integers"
}))
end
This would be the updated unban script itself, regardless of the issue above even if the script above did allow for users to be added to the list if they weren’t in-game unbanAsync requires the Parameters to be wrapped in a table, with unbanAsync you can also bulk unban so you don’t need to send 25 different unbanAsync request to unban 25 users instead you can use the original list and just unban all 25 of those users at the same time.
If it errors on a particular user according to the PlayerService docs for BanAPI it’ll join all the errors together separated by a comma.
For example, if this method is invoked for five UserIds: {1, 2, 3, 4, 5} and requests for users 2 and 4 fail then the following error message appears: HTTP failure for UserId 2: Timedout, HTTP 504 (Service unavailable) failure for UserId 4: Service exception.
I’ve utilized that with the CommandContext | Reply to differentiate the error messages and the final request.
local PlayerService = game:GetService("Players")
return function (context, Players)
local config: UnbanConfigType = {
UserIds = Players,
ApplyToUniverse = false
}
local success, err = pcall(function()
return PlayerService:UnbanAsync(config)
end)
if not success then
local formatError = string.split(err, ",")
local failedRequest = #formatError
for _, readError in formatError do
context:Reply(readError, Color3.fromRGB(177, 49, 49))
end
return `Unbanned {#Players - failedRequest} player(s), {failedRequest} request failed.`
end
return `Unbanned {#Players} player(s).`
end
Oh my god you’re an actual legend
Thanks so much
Is there any way you could do the same with the “Player” system to allow it for offline players too or is that not possible?
EDIT: I just testing this out and it doesn’t seem to be working, no errors though it does say “Unbanned 1 player(s)” so it seems to be working?
It does work for offline users although it won’t have the autofill like it does with users that are in that server.
With it not working I enabled “ApplyToUniverse” and that seemed to work.
local config: UnbanConfigType = {
UserIds = Players,
ApplyToUniverse = true
}
Hey, for anyone that needs help hiding the gui for people that aren’t supposed to use it, here is what you can add into the local script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Cmdr = require(ReplicatedStorage:WaitForChild("CmdrClient"))
local playerRank = game.Players.LocalPlayer:GetRankInGroup(123456789) -- add group id here
if playerRank >= 1 then -- obviously change this or everyone in the group will have access to it
Cmdr:SetActivationKeys({ Enum.KeyCode.F2 }); -- this can also be changed
else
Cmdr:SetEnabled(false);
end
You can implement your own checking system, but this is a good base to work off (and there is no other scripts or remote events involved!)
Hey, I sent you a DM, can you respond to it? thx
Alright so I have a dynamic argument system, I’ve checked the docs but it won’t work.
Output:
ReplicatedStorage.CmdrClient.Shared.Util:115: invalid argument #1 to 'gmatch' (string expected, got nil) - Client - Util:115
18:13:01.040 Stack Begin - Studio
18:13:01.040 Script 'ReplicatedStorage.CmdrClient.Shared.Util', Line 115 - function SplitStringSimple - Studio - Util:115
18:13:01.040 Script 'ReplicatedStorage.CmdrClient.Shared.Util', Line 250 - function ParsePrefixedUnionType - Studio - Util:250
18:13:01.040 Script 'ReplicatedStorage.CmdrClient.Shared.Argument', Line 34 - function new - Studio - Argument:34
18:13:01.040 Script 'ReplicatedStorage.CmdrClient.Shared.Command', Line 62 - function Parse - Studio - Command:62
18:13:01.041 Script 'ReplicatedStorage.CmdrClient.Shared.Dispatcher', Line 44 - function Evaluate - Studio - Dispatcher:44
18:13:01.041 Script 'ReplicatedStorage.CmdrClient.CmdrInterface', Line 31 - function OnTextChanged - Studio - CmdrInterface:31
18:13:01.041 Script 'ReplicatedStorage.CmdrClient.CmdrInterface.Window', Line 341 - Studio - Window:341
18:13:01.041 Stack End - Studio
18:13:01.125 ReplicatedStorage.CmdrClient.Shared.Util:115: invalid argument #1 to 'gmatch' (string expected, got nil) - Client - Util:115
18:13:01.125 Stack Begin - Studio
18:13:01.125 Script 'ReplicatedStorage.CmdrClient.Shared.Util', Line 115 - function SplitStringSimple - Studio - Util:115
18:13:01.125 Script 'ReplicatedStorage.CmdrClient.Shared.Util', Line 250 - function ParsePrefixedUnionType - Studio - Util:250
18:13:01.125 Script 'ReplicatedStorage.CmdrClient.Shared.Argument', Line 34 - function new - Studio - Argument:34
18:13:01.126 Script 'ReplicatedStorage.CmdrClient.Shared.Command', Line 62 - function Parse - Studio - Command:62
18:13:01.126 Script 'ReplicatedStorage.CmdrClient.Shared.Dispatcher', Line 44 - function Evaluate - Studio - Dispatcher:44
18:13:01.126 Script 'ReplicatedStorage.CmdrClient.CmdrInterface', Line 31 - function OnTextChanged - Studio - CmdrInterface:31
18:13:01.126 Script 'ReplicatedStorage.CmdrClient.CmdrInterface.Window', Line 341 - Studio - Window:341
18:13:01.126 Stack End - Studio
18:13:01.744 ReplicatedStorage.CmdrClient.Shared.Util:115: invalid argument #1 to 'gmatch' (string expected, got nil) - Client - Util:115
18:13:01.744 Stack Begin - Studio
18:13:01.744 Script 'ReplicatedStorage.CmdrClient.Shared.Util', Line 115 - function SplitStringSimple - Studio - Util:115
18:13:01.744 Script 'ReplicatedStorage.CmdrClient.Shared.Util', Line 250 - function ParsePrefixedUnionType - Studio - Util:250
18:13:01.744 Script 'ReplicatedStorage.CmdrClient.Shared.Argument', Line 34 - function new - Studio - Argument:34
18:13:01.745 Script 'ReplicatedStorage.CmdrClient.Shared.Command', Line 62 - function Parse - Studio - Command:62
18:13:01.745 Script 'ReplicatedStorage.CmdrClient.Shared.Dispatcher', Line 44 - function Evaluate - Studio - Dispatcher:44
18:13:01.745 Script 'ReplicatedStorage.CmdrClient.CmdrInterface', Line 31 - function OnTextChanged - Studio - CmdrInterface:31
18:13:01.745 Script 'ReplicatedStorage.CmdrClient.CmdrInterface.Window', Line 341 - Studio - Window:341
18:13:01.746 Stack End - Studio
Script (client):
return {
Name = "clans";
Description = "Everything related to the clans system.";
Group = "Moderator";
Args = {
{
Type = "string";
Name = "clan";
Description = "The clan to change.";
},
function(context)
return {
Type = context.Cmdr.Util.MakeEnumType("option", {"Disband", "Kick", "Change Owner", "Change Rank", "Edit Info"}),
Name = "action",
Description = "The action you would like to do.",
}
end,
function(context)
local action = context:GetArgument(2):GetValue()
if action == "Change Rank" then
return {
{
Type = "player";
Name = "player";
Description = "Player whose rank is being changed.";
},
{
Type = context.Cmdr.Util.MakeEnumType("option", {"High Commander", "Captain", "Member"}),
Name = "rank",
Description = "Rank to change player to.",
}
}
elseif action == "Kick" then
return {
{
Type = "player";
Name = "player";
Description = "Player who is being kicked.";
}
}
elseif action == "Change Owner" then
return {
{
Type = "player";
Name = "newOwner";
Description = "Player who will be the new owner.";
}
}
elseif action == "Edit Info" then
return {
{
Type = "string";
Name = "description";
Description = "New description for the clan.";
},
{
Type = "integer";
Name = "imageid";
Description = "(optional) New image ID for the clan.";
Optional = true;
}
}
end
end
};
}
Is there any reason why this won’t work? I am certain it is not the server that is erroring.
I would use it if you guys added more built in commands like warn and ban
This system is made to allow you to create your own commands, if they included a bunch of commands people won’t use this system as it was originally created to be.
This system was created to be both functional and allow for the developer add/remove what commands they want being tailored towards that particular game. Making those commands aren’t hard at all but its up to you as to how you’d want to implement them.
To this day still my favorite admin system, use it in all my games