Need Help With Admin Commands

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? I want to create an admin commands that work on individual players, as well as tags such as “me”, “others”, “admins”, “all”, etc.

  2. What is the issue? I was able to figure out how to use “me”, but I’m not sure how to make multiple players be teleported to one, how to speed up multiple players, etc.

Here is my code:

local admins = {
	"TheVeryBoredCat",
	"FPMFP",
	"Player1",
	"Player2",
}

local prefix = "/"

--SERVICES AND LOCATIONS
local storage = game:GetService("ReplicatedStorage")

--COMMAND LIST
local commands = {}

--FUNCTIONS AND THE CODE ITSELF
local function isAdmin(plr) --OBJECT VERSION OF PLR
	for _, v in pairs(admins) do
		if v == plr.Name then
			return true
		end
	end
	return false
end

local function findPlr(name, sender)
	local plrs = game.Players:GetPlayers()
	for i, plr in pairs(plrs) do
		if string.lower(plr.Name) == name then
			return plr --STRING VERSION OF PLR
		elseif name == "me" then
			return sender
		end
	end
	return nil
end

commands.tp = function(sender, args) --SENDER IS AN OBJECT | ARGS ARE TABLE OF STRINGS
	print ("Teleport function fired by "..sender.Name)
	for _, plrName in pairs(args) do
		print(plrName)
	end
	local plrTpingName = args[1]
	local plrTpingToName = args[2]
	if plrTpingName and plrTpingToName then
		local plrTping = findPlr(plrTpingName, sender)
		local plrTpingTo = findPlr(plrTpingToName, sender)
		if plrTpingName and plrTpingToName then
			plrTping.Character.HumanoidRootPart.CFrame = plrTpingTo.Character.HumanoidRootPart.CFrame
			print("Teleport Successful")
		end
	end
end

commands.speed = function(sender, args)
	print ("Speed function fired by "..sender.Name)
	local plrToSpeed = args[1]
	local walkSpeed = args[2]
	if plrToSpeed then
		local plr = findPlr(plrToSpeed, sender)

		if plr then
			plr.Character.Humanoid.WalkSpeed = tonumber(walkSpeed)
			print(plrToSpeed.." was given WalkSpeed ".. walkSpeed)
		end
	end
end

game.Players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function()
		plr.Chatted:Connect(function(msg, recipient)
			if isAdmin(plr) then
				msg = string.lower(msg)
				local splitString = msg:split(" ")
				local arg1 = splitString[1]
				local cmd = arg1:split(prefix)
				local cmdName = cmd[2]
				if commands[cmdName] then
					local args = {}
					for i = 2, #splitString, 1 do
						table.insert(args, splitString[i])
					end
					commands[cmdName](plr, args)
				end
			end
		end)
	end)
end)
  1. What solutions have you tried so far? I have looked for solutions on the DevHub, here on the DevForum, and on other online resources, but I could not find a solution.
7 Likes

This is probably what you are looking for
you should use tables for the players if you are considering using multiple of them

Admin script
local admins = {
	"TheVeryBoredCat",
	"FPMFP",
	"Player1",
	"Player2",
}

local prefix = "/"

--SERVICES AND LOCATIONS
local storage = game:GetService("ReplicatedStorage")

--COMMAND LIST
local commands = {}

--FUNCTIONS AND THE CODE ITSELF
local function isAdmin(plr) --OBJECT VERSION OF PLR
	for _, v in pairs(admins) do
		if v == plr.Name then
			return true
		end
	end
	return false
end

local function findPlr(name, sender)
	local plrs = game.Players:GetPlayers()
	for i, plr in pairs(plrs) do
		if string.lower(plr.Name) == name then
			return plr --STRING VERSION OF PLR
		elseif name == "me" then
			return {sender}
		elseif name == "others" then
			local PlayersSelected = {}
			for i,v in pairs(game.Players:GetPlayers()) do
				if v ~= sender then
					table.insert(PlayersSelected,v)
				end
				end
			return PlayersSelected
		elseif name == "all" then
			return game:GetService("Players"):GetPlayers()
		elseif name == "admins" then
			local PlayersSelected = {}
			for i,v in pairs(game.Players:GetPlayers()) do
				for i2,v2 in pairs(admins) do
					if v.Name == v2 then
						table.insert(PlayersSelected,v)
						end
				end
			end
			return PlayersSelected
			end
		
	end
	return nil
end

commands.tp = function(sender, args) --SENDER IS AN OBJECT | ARGS ARE TABLE OF STRINGS
	print ("Teleport function fired by "..sender.Name)
	for _, plrName in pairs(args) do
		print(plrName)
	end
	local plrTpingName = args[1]
	local plrTpingToName = args[2]
	if plrTpingName and plrTpingToName then
		local plrTping = findPlr(plrTpingName, sender)
		local plrTpingTo = findPlr(plrTpingToName, sender)
		for i,v in pairs(plrTping) do
			v.Character.HumanoidRootPart.CFrame = plrTpingTo[1].Character.HumanoidRootPart.CFrame
			print("Teleport Successful")
		end
	end
end

commands.speed = function(sender, args)
	print ("Speed function fired by "..sender.Name)
	local plrToSpeed = args[1]
	local walkSpeed = args[2]
	if plrToSpeed then
		local plr = findPlr(plrToSpeed, sender)

		for i,v in pairs(plr) do
			plr.Character.Humanoid.WalkSpeed = tonumber(walkSpeed)
			print(plrToSpeed.." was given WalkSpeed ".. walkSpeed)
		end
	end
end

game.Players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function()
		plr.Chatted:Connect(function(msg, recipient)
			if isAdmin(plr) then
				msg = string.lower(msg)
				local splitString = msg:split(" ")
				local arg1 = splitString[1]
				local cmd = arg1:split(prefix)
				local cmdName = cmd[2]
				if commands[cmdName] then
					local args = {}
					for i = 2, #splitString, 1 do
						table.insert(args, splitString[i])
					end
					commands[cmdName](plr, args)
				end
			end
		end)
	end)
end)
2 Likes

Hi there,

Incorporating your needs, below would be a modified version of your findPlr function which will handle all-around “getting players” in general. The approach is driven by a consistent table that is actively populated and flushed returning the “select” player or applicable group of players.

local function findPlrs(name, sender)
	name = name:lower()
	
	local plrs = game.Players:GetPlayers()
	local targets = {}
	
	for i, plr in pairs(plrs) do
		if string.lower(plr.Name) == name then
			table.insert(targets, plr)
			break
		end
	end
	
	if name == "me" then
		table.insert(targets, sender)
	elseif name == "all" then
		for i, plr in pairs(plrs) do
			table.insert(targets, plr)
		end
	elseif name == "others" then
		for i, plr in pairs(plrs) do
			if plr.Name ~= sender.Name then
				table.insert(targets, plr)
			end
		end
	elseif name == "admins" then
		for i, plr in pairs(plrs) do
			if table.find(admins, plr.Name) then
				table.insert(targets, plr)
			end
		end
	elseif string.find(name, ",") then
		local split = string.split(name, ",")
		
		for i, plr in pairs(plrs) do
			if table.find(split, plr.Name) then
				table.insert(targets, plr)
			end
		end
	end
	
	return targets
end

In addition to me, all, others, and admins, it also supports for multiple specified comma-separated players as an argument, such as /speed player1,player2,player3 80. The function will always return a table of players, which you can then check in your individual command implementation if it is empty or not using next(findPlrs(targets, sender), returning nil if empty.

An example command execution with this approach would look like this:

commands.someCommand = function(sender, args)
	local target = args[1]
	
	local targets = findPlrs(target)
	if next(targets) then
		for i,v in pairs(targets) do
			print(target.Name)
		end
	end
end

This method can be especially helpful when you want a consistent response type from the findPlr() function, knowing that it will always be a table (empty or not), which can make command handling and further sanity checks a bit easier and consistent throughout the system.

Below is an example execution with this approach, applied to your speed command:

commands.speed = function(sender, args)
	print ("Speed function fired by "..sender.Name)
	local plrToSpeed = args[1]
	local walkSpeed = args[2]
	if plrToSpeed and walkSpeed then
		local plrs = findPlrs(plrToSpeed, sender)

		if next(plrs) then
			for i,v in pairs(plrs) do
				v.Character.Humanoid.WalkSpeed = tonumber(walkSpeed)
				print(v.Name.." was given WalkSpeed ".. walkSpeed)
			end
		end
	end
end

Keep in mind that the above code snippets should be treated as templates that you can further amend and match your needs. Feel free to report back on any issues you may find.

5 Likes

thanks, this is looking a lot better, however, the speed command isn’t working because of an error on line 83 where it says

plr.Character.Humanoid.WalkSpeed = tonumber(walkSpeed)

it says that Humanoid can not be assigned to nil.

Furthermore, for both the tp and speed commands, if I use a username instead of a keyword like “me” it will say that the code is expecting tables, not instances.

1 Like

Thank you so much! Can you further explain this so I know what exactly allowed this to work?

Sure.

So the core principle here is that findPlrs() will always return a table. That acts as a measure of convenience that assures you that you will not need to check the type of data returned (Player object, array, etc.).

The function works simply by cycling through every player in the server upon each iteration, handpicking only specific players that the command is supposed to be executed on.

For example, if you’re just trying to execute the command on all admins in the server,

if name == "admins" then
	for i, plr in pairs(plrs) do
		if table.find(admins, plr.Name) then
			table.insert(targets, plr)
		end
	end
end

The function begins with the targets table being completely empty, ready to be filled with specified players and returns them. In the above example, when triggering a command such as /speed admins 80, the function checks if there’s any player in the server whose name matches any elements in the admins table that you already have in your code. If so, it’ll populate the targets table with it. At the end of the loop, it’ll return what it just gathered and then you can use that returned table as an array of all players that the command will be executed on.

local plrs = findPlrs("admins", sender) -- Returns a table of players the command is supposed to run on.

if next(plrs) then -- Check if the function returned an empty table
	for i,player in pairs(plrs) do -- If not, loop through each player returned by the function
		print("Command ran on "..player.Name) -- Perform any action
	end
end

Above is how you can process the returned value from findPlrs() with a consistent check throughout each command you have of if next(plrs) then. The next keyword returns nil when supplied with an empty table {}, where you can check if the function returned any results at all. If so, then you can look through each element in it, knowing it is the correct player picked for the command to be ran on, and handle the rest individually as you’d normally otherwise do.

Hope that clarifies any potential doubts and helps you with your further implementation.

2 Likes

That was really helpful but I have one more thing (sorry).

How could I convert this segment of the findPlrs function to work to find a player with only a few letters, for example “thev” to return “theveryboredcat”?

elseif string.find(name, ",") then
		local split = string.split(name, ",")

		for i, plr in pairs(plrs) do
			if table.find(split, plr.Name) then
				table.insert(targets, plr)
			end
		end
	end

No worries.

This is completely untested but give it a shot. This should work with simple single-player arguments /speed thever 80 and comma-separated /speed thever,zedd 80 both. The method works simply by matching part of the player’s username with any player in the server, instead of matching the exact player’s name.

Below is the updated findPlrs() function to include these changes. Although, I’d highly recommend you test it and report back with any issues, if found.

local function findPlrs(name, sender)
	name = name:lower()

	local plrs = game.Players:GetPlayers()
	local targets = {}

	for i, plr in pairs(plrs) do
		if plr.Name:lower():sub(1,#name) == name:lower() then
			table.insert(targets, plr)
			break
		end
	end

	if name == "me" then
		table.insert(targets, sender)
	elseif name == "all" then
		for i, plr in pairs(plrs) do
			table.insert(targets, plr)
		end
	elseif name == "others" then
		for i, plr in pairs(plrs) do
			if plr.Name ~= sender.Name then
				table.insert(targets, plr)
			end
		end
	elseif name == "admins" then
		for i, plr in pairs(plrs) do
			if table.find(admins, plr.Name) then
				table.insert(targets, plr)
			end
		end
	elseif string.find(name, ",") then
		local split = string.split(name, ",")
		
		for i, plr in pairs(plrs) do
			for _, individual in pairs(split) do
				if plr.Name:lower():sub(1,#name) == individual:lower() then
					table.insert(targets, plr)
				end
			end
		end
	end

	return targets
end
3 Likes

Thank you so much. This will help me a lot as I continue learn scripting and work on my own systems. Have a good day

2 Likes

You can try using a GUI for this, it’ll be much simpler :smiley:

i wanted to only use chat :stuck_out_tongue: but I’m very aware

1 Like

You can find some tutorials on YouTube :smiley:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.