How to set this up? i can’t do it
What part are you struggling with? Have you read the tutorial in Cmdr’s website? I’ll summarize the basic setup from their site.
Server:
-- An example from Cmdr's website
-- This is a script you would create in ServerScriptService, for example.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Cmdr = require(path.to.Cmdr)
Cmdr:RegisterDefaultCommands() -- This loads the default set of commands that Cmdr comes with. (Optional)
-- Cmdr:RegisterCommandsIn(script.Parent.CmdrCommands) -- Register commands from your own folder. (Optional)
Cmdr:RegisterHooksIn(path.to.Hooks) -- Register the BeforeRun hook
Client:
-- An example from Cmdr's website
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Cmdr = require(ReplicatedStorage:WaitForChild("CmdrClient"))
-- Configurable, and you can choose multiple keys
Cmdr:SetActivationKeys({ Enum.KeyCode.F2 })
In another folder (in this example CmdrCommands
), define the custom command and its behavior.
A ModuleScript named Teleport
(or whatever else you want it to be):
-- An example from Cmdr's website
-- Teleport.lua, inside your commands folder as defined above.
return {
Name = "teleport";
Aliases = {"tp"};
Description = "Teleports a player or set of players to one target.";
Group = "Admin";
Args = {
{
Type = "players";
Name = "from";
Description = "The players to teleport";
},
{
Type = "player";
Name = "to";
Description = "The player to teleport to"
}
};
}
Another ModuleScript, this time named TeleportServer
:
-- An example from Cmdr's website
-- TeleportServer.lua
-- These arguments are guaranteed to exist and be correctly typed.
return function (context, fromPlayers, toPlayer)
if toPlayer.Character and toPlayer:FindFirstChild("HumanoidRootPart") then
local position = toPlayer.Character.HumanoidRootPart.CFrame
for _, player in ipairs(fromPlayers) do
if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
player.Character.HumanoidRootPart.CFrame = position
end
end
return "Teleported players."
end
return "Target player has no character."
end
You will also need to setup a BeforeRun hook, otherwise Cmdr will not run. I will put this inside a folder called Hooks
in this example, but you can call it whatever you want
-- An example from Cmdr's website
-- A ModuleScript inside your hooks folder.
return function (registry)
registry:RegisterHook("BeforeRun", function(context)
if context.Group == "DefaultAdmin" and context.Executor.UserId ~= game.CreatorId then
return "You don't have permission to run this command"
end
end)
end
And finally, in the same server script where we registered Cmdr’s default commands, register the custom commands and hooks. Here’s how you would do it:
Cmdr:RegisterCommandsIn(script.Parent.CmdrCommands) -- Register commands from your own folder. (Optional)
Cmdr:RegisterHooksIn(path.to.Hooks) -- Register the BeforeRun hook
I wrote this up in like 10 minutes so it might be a bit sloppy but hope this helps!
I would suggest changing your type to this:
local Players = game:GetService("Players")
if not game:IsLoaded() then
game.Loaded:Wait()
end
local treasures = Players.LocalPlayer:WaitForChild("Treasures")
return function(registry)
local Util = registry.Cmdr.Util
local treasureNames = Util.GetNames(treasures:GetChildren())
table.sort(treasureNames) -- Guarantees the same order in the list
registry:RegisterType("treasure",
Util.MakeEnumType(
"TreasureName",
treasureNames
)
)
end
Hello!!
I’m currently stuck on something with Cmdr. I’m trying to make a command that utilizes multiple custom types. However I want one of the arguments to pick a specific type depending on it’s previous argument.
Here’s a picture to show what I mean.
Any help is super appreciated!!
Thanks in advance!
We call this dynamic arguments. I’m not sure if this is covered in the current documentation site (which is quite out of date), but it is mentioned on the Beta documentation site: https://eryn.io/Cmdr/beta/docs/commands#dynamic-arguments-and-inline-types
Thanks a bunch, yeah I’ve noticed that the newer site has a lot of missing things like Dynamic Arguments. This was exactly what I needed!
Now that the new Roblox ban API has come out, who agrees with me that there should be a ban command, unban command, and checkban command by default?
There’s two things that I would like for my project, are these able to be done on cmdr or is there an alternative with these that I could use?
- Is there a way to have optional arguments? like you could set it to this or that, or just leave it blank to do both.
- Is there a way to have a system where if you press enter and you don’t have a valid command typed in, instead of executing it will autocomplete the top result?
Autocomplete Example
If I were to press enter here, it would put the whole “clear” command into the box
(NOT EXECUTE IT)
Yes.
Just use tab for autocompletion, but I am sure it might be possible to tweak it to use the enter key.
Sorry i must have missed that part about using tab for autocomplete
Nice! How can I validate the user is in one of the permitted groups?
I didn’t see any replies here mentioning support for Player’s DisplayNames, so I thought I’d include my remake of the Player type. The AutoComplete now includes DisplayNames in the format “DisplayName @Username”.
New Player type module
local Util = require(script.Parent.Parent.Shared.Util)
local Players = game:GetService("Players")
local function GetDisplayNamePair(list)
local names = {}
for _,player in list do
table.insert(names, `{player.DisplayName} @{player.Name}`)
end
return names
end
local playerType = {
Transform = function (text)
local findPlayer = Util.MakeFuzzyFinder(Players:GetPlayers())
local result = findPlayer(text)
if not result or #result == 0 then
local list = GetDisplayNamePair(Players:GetPlayers())
findPlayer = Util.MakeFuzzyFinder(list)
local fResult = findPlayer(text)
result = {}
for _,found in fResult do
table.insert(result, Players:FindFirstChild(found:split("@")[2]))
end
end
return result
end;
Validate = function (players)
return #players > 0, "No player with that name could be found."
end;
Autocomplete = function (players)
return GetDisplayNamePair(players)
end;
Parse = function (players)
return players[1]
end;
Default = function(player)
return player.Name
end;
ArgumentOperatorAliases = {
me = ".";
all = "*";
others = "**";
random = "?";
};
}
return function (cmdr)
cmdr:RegisterType("player", playerType)
cmdr:RegisterType("players", Util.MakeListableType(playerType, {
Prefixes = "% teamPlayers";
}))
end
This is especially useful if your game displays Players with only their DisplayName, and you want to avoid the extra effort of opening the Roblox menu to check who’s who.
I’m having an issue with creating types. I’ve tried everything.
Each time Autocomplete
(except for the initial function) is called, this error is called.
00:41:36.568 ReplicatedStorage.CmdrClient.CmdrInterface.AutoComplete:122: attempt to perform arithmetic (sub) on nil and number - Client - AutoComplete:122
00:41:36.568 Stack Begin - Studio
00:41:36.568 Script 'ReplicatedStorage.CmdrClient.CmdrInterface.AutoComplete', Line 122 - function Show - Studio - AutoComplete:122
00:41:36.568 Script 'ReplicatedStorage.CmdrClient.CmdrInterface', Line 84 - function OnTextChanged - Studio - CmdrInterface:84
00:41:36.568 Script 'ReplicatedStorage.CmdrClient.CmdrInterface.Window', Line 328 - Studio - Window:328
00:41:36.568 Stack End - Studio
Here is the type code:
ANOMALYTYPAGE = {
[1] = "ItsPlasmaRBLX2",
[2] = "Packages",
[3] = "Spigot",
[4] = "Brick"
}
local Util = require(script.Parent.Parent.Shared.Util)
local anomalyTypageFinder = Util.MakeFuzzyFinder(ANOMALYTYPAGE)
local storedKeyType = {
Validate = function(anomalyName : string)
if typeof(anomalyName) == "string" then
return ANOMALYTYPAGE[anomalyName] ~= nil, "No anomaly with that name could be found."
end;
return false, "Anomaly name must be a string"
end;
Transform = function(text)
return anomalyTypageFinder(text)
end;
Autocomplete = function(anomalyName)
return Util.GetNames(ANOMALYTYPAGE)
end;
Parse = function(anomalyName : string)
return anomalyName
end;
}
return function (cmdr)
cmdr:RegisterType("anomaly", storedKeyType)
cmdr:RegisterType("anomalies", Util.MakeListableType(storedKeyType))
end
Side note, even if the Autocomplete
function is called it will throw an error, regardless of what is in the function. This means if the function is blank, it will still throw an error.
Apparently in the AutoComplete
master function the variable start, stop
returns nil for my type.
My work around was adding a continue condition. Surprisingly the type’s autocomplete works.
anyone got any idea why im having a issue? hwenever i utilize cmdr, the script says "CMDR disabled for security, BEforeRun not setup or something?
That’s because for safety, you can’t run any commands until you setup a BeforeRun hook. Read the documentation to learn more on how to set it up. The link will take you to the beta version of the Cmdr docs. For clarification, a BeforeRun hook is what you will use for command permissions. It will check if the player attempting to execute the command is allowed to but you can define custom behavior/logic because you’re going to be the one writing it.
It is setup… It says it is not however.
Then you probably didn’t do it correctly. The error clearly says you didn’t set up the BeforeRun hook. How did you set it up? Can you provide the code you used?
is it possible to make the CMDR usable only to specific people?
I’m having a very weird issue with Cmdr. I am making a viewstats command so that my Moderators can view other players stats by typing their username with the auto-complete menu if they’re in the server or use the @ prefix to type their full username if they’re not in the server. However, the issue is that when Cmdr gets to a point where it needs to return something inside the command, it just doesn’t. And that happens for every command for some really weird reason. After using commands a bunch more times, the very delayed command responses I should’ve gotten ages ago finally appear.
I tried using print statements and they got where they needed to. Once it gets to a return statement, it just self destructs.
Note: The game uses ProfileService and the game is called RoKarate. You can search it using the search bar and it’ll be the first game. I have confirmed that every variable gives what it’s supposed to such as the DataManager existing and the DataManager giving the current profile if they are in the server and all that.
Here is the following code I used:
return {
Name = "viewstats",
Aliases = {"stats"},
Description = "View a players stats.",
Group = "Moderator",
Args = {
{
Type = "player @ string",
Name = "player @ username",
Description = "The full username of the player."
}
}
}
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local DataManager = require(ServerStorage.DataManager) -- This does exist
local Format = require(ReplicatedStorage.Modules.FormatNumber.Simple) -- This does exist
local function toDHMS(seconds)
local days = math.floor(seconds / 86400)
local hours = math.floor((seconds % 86400) / 3600)
local minutes = math.floor((seconds % 3600) / 60)
local seconds = math.floor(seconds % 60)
return ("%i:%02i:%02i:%02i"):format(days,hours,minutes,seconds)
end
return function(context, player)
if typeof(player) == "Instance" then
local profile = DataManager:GetProfile(player) -- This does work
context:Reply(player.Name.."'s stats:")
context:Reply("---------------------------------------------")
context:Reply("Belt: "..profile.Data.Belt)
context:Reply("Strength: "..Format.Format(profile.Data.Strength))
context:Reply("Health: "..Format.Format(profile.Data.Health))
context:Reply("MaxStamina: "..Format.Format(profile.Data.MaxStamina))
context:Reply("Wins: "..Format.Format(profile.Data.Wins))
context:Reply("Kills: "..Format.Format(profile.Data.TotalKills))
context:Reply("Robux Donated: "..Format.Format(profile.Data.RobuxDonated))
context:Reply("Playtime: "..toDHMS(profile.Data.Playtime))
context:Reply("---------------------------------------------")
return "Successfully retrieved the players stats."
elseif typeof(player) == "string" then
local gotUserId, userId = pcall(function()
return Players:GetUserIdFromNameAsync(player)
end)
if not gotUserId then
return `Failed to get UserId associated with {player}.\nError: {userId}`
end
local profileStore = DataManager:GetProfileStore()
local profile = profileStore:ViewProfileAsync("Player_"..userId)
if profile == nil then
return player.." does not have any data!"
end
context:Reply(player.."'s stats:")
context:Reply("---------------------------------------------")
context:Reply("Belt: "..profile.Data.Belt)
context:Reply("Strength: "..Format.Format(profile.Data.Strength))
context:Reply("Health: "..Format.Format(profile.Data.Health))
context:Reply("MaxStamina: "..Format.Format(profile.Data.MaxStamina))
context:Reply("Wins: "..Format.Format(profile.Data.Wins))
context:Reply("Kills: "..Format.Format(profile.Data.TotalKills))
context:Reply("Robux Donated: "..Format.Format(profile.Data.RobuxDonated))
context:Reply("Playtime: "..toDHMS(profile.Data.Playtime))
context:Reply("---------------------------------------------")
return "Successfully retrieved the players stats."
end
end