Super basic admin commands tutorial that should fit all your needs

Hello, I am SpacePuppy2! I really want a name change lol
Anyways, this is going to be a super basic tutorial on admin commands. In this tutorial, you will learn about string:split() and more. Without any delay, lets get started.

Please note, this is my first tutorial!

1: Inserting our Script.

For starters, we need to insert a script into ServerScriptService. You can put it in workspace too, but I prefer SSS.

Question: Why not a module script or local script?
A: Those all serve different purposes that I will not cover here.

These kinds of scripts are called Server Scripts. They control how the game works and can control what others see on their screen. When inserting the script, delete all the code inside it so it is empty. Now lets start step 2.

2: Setting up our script.

For our second step, we will begin by setting it up so the functions later can work.

Lets create a table in our script. This should be the first line:

local admins = {"SpacePuppy2","UsernameHere!"}

You can picture tables like boxes. Boxes that hold information, or even other boxes. Tables are created with curly brackets {}, and hold info we put in them. In this case, we put strings in them. Strings are text. Players’ usernames are text strings. We will fill our “box” (table) with their usernames.

Replace my username and the admins you want. It isn’t case sensitive with capitals, but it must be their full username. To add more, just do something like this:

local admins = {"Someone","Someone","Username","Username2"}

Just put their names in " marks. MAKE SURE TO SEPERATE THEM WITH COMMAS LIKE I DID!!!

Next, lets make an empty table for our commands.

local admins = {} -- Put your admins' usernames here!!!
local commands = {} -- Empty table that stores our commands.

We will leave it empty, for now. Lets make one last variable, our prefix!

local admins = {}
local commands = {}
local prefix = "/" -- The prefix is also a text string! This is why it is in " marks.

The prefix is the thing we put before our command, like so:
/ban player or :ban player

You can set this to whatever symbol you like. Lets continue to the next step.

3: Scripting our first functions!

So far, your code should look something similar this:

local admins = {}
local commands = {}
local prefix = "/"

Lets write our first function. This will check if they are a real player or not when player’s chat commands.

local admins = {}
local commands = {}
local prefix = "/"

local function findPlayer(name,sender)
	for _,player in pairs(game.Players:GetPlayers()) do
		if string.lower(name) == "me" then
			return sender
		elseif string.lower(player.Name) == name then
			return player
		end
	end
	
	return nil
end

This probably looks VERY complicated. That is because it somewhat is, but I will break it down for you guys! All this does is look through every player in the game and uses return if the player exists. We use this function like so:

findPlayer("ExampleUserName")

-- This would return the player named "ExampleUserName", if there is one!

You may wonder what string.lower is. All that does is convert a piece of text into all lowercase. We do this so that capital letters do not matter.

OUR NEXT FUNCTION: isAdmin()
Lets add another function to our code; isAdmin(). As the name suggests, it tells us if someone is an admin or not. Lets add it to our code, like so:

local admins = {}
local commands = {}
local prefix = "/"

local function findPlayer(name,sender)
	for _,player in pairs(game.Players:GetPlayers()) do
		if string.lower(name) == "me" then
			return sender
		elseif string.lower(player.Name) == name then
			return player
		end
	end
	
	return nil
end

local function isAdmin(player)
	for _,Admin in pairs(admins) do
		if string.lower(Admin) == string.lower(player.Name) then
			return true
		end
	end
	
	return false
end

Our next function is isAdmin(). This returns true or false. We give it a text string, and it searches to see if there is a player with that name in the admins table.

4: Scripting the chat system itself.

Your code should now feature these two new functions!

local admins = {}
local commands = {}
local prefix = "/"

local function findPlayer(name,sender)
	for _,player in pairs(game.Players:GetPlayers()) do
		if string.lower(name) == "me" then
			return sender
		elseif string.lower(player.Name) == name then
			return player
		end
	end
	
	return nil
end

local function isAdmin(player)
	for _,Admin in pairs(admins) do
		if string.lower(Admin) == string.lower(player.Name) then
			return true
		end
	end
	
	return false
end

We will now start to script the function where we check if they said a command when they speak. Lets start with this now:

game.Players.PlayerAdded:Connect(function(player)
    player.Chatted:Connect(function(message)
       if isAdmin(player) then
          
       end
    end)
end)

This connects the player joining and them sending a chat message. We simply add a check if they are an admin. If they are, lets continue and see if they chatted a command!

game.Players.PlayerAdded:Connect(function(player)
    player.Chatted:Connect(function(message)
       if isAdmin(player) then
          -- an admin is here! lets see if they chat a command!
          message = string.lower(message)
			
		local splitString = message:split(" ")
		local slashCommand = splitString[1]
		local cmd = slashCommand:split(prefix)
		local cmdName = cmd[2]
			
		if commands[cmdName] then
			local arguments = {}
				
			for i = 2, #splitString, 1 do
				table.insert(arguments, splitString[i])
			end
				
			commands[cmdName](player,arguments)
		end

       end
    end)
end)

Lets break this MASSIVE piece of code down now.

message = string.lower(message)

This is the part where we simply convert whatever they said into all lowercase. Just for quality of life improvements :slight_smile:

local splitString = message:split(" ")
local prefixCommand = splitString[1]
local cmd = prefixCommand:split(prefix)
local cmdName = cmd[2]

This part of the code is where we break down what they said.
splitString is whatever they said in a table, all separated by a space. Here is a visual of what that would look like:

{"something","i","said","in","chat"}

prefixCommand is the first thing in that table. If I said something like:

{"/ban","bob"}

in chat, prefixCommand is the first thing there. That would be "/ban".

Next, we breakdown prefixCommand even more! This is where we actually get what command they wanted. Say prefixCommand was this:

{"/ban"}

cmd would be:

{"/","ban"}

Finally, cmdName is just the second thing inside of cmd. For example:

local cmd = {"/","ban"}
local cmdName = cmd[2]
print(cmdName) -- Would output "ban"

It just gets the second thing in that table, which just so happens to be the command name!
Finally, lets talk about this:

if commands[cmdName] then
	local arguments = {}
				
	for i = 2, #splitString, 1 do
		table.insert(arguments, splitString[i])
	end
				
	commands[cmdName](player,arguments)
end

First we check if the command even exists by doing commands[cmdName].
Next, if it does exist, we make an empty table for the names of the players who we want to run the command on; local arguments = {}

Then we add the player names and stuff into the arguments table and run our command!

5: Actually making a working command!
CURRENT CODE:
local admins = {}
local commands = {}
local prefix = "/"

local function findPlayer(name,sender)
 for _,player in pairs(game.Players:GetPlayers()) do
 	if string.lower(name) == "me" then
 		return sender
 	elseif string.lower(player.Name) == name then
 		return player
 	end
 end
 
 return nil
end

local function isAdmin(player)
 for _,Admin in pairs(admins) do
 	if string.lower(Admin) == string.lower(player.Name) then
 		return true
 	end
 end
 
 return false
end

game.Players.PlayerAdded:Connect(function(player)
 player.Chatted:Connect(function(message)
    if isAdmin(player) then
       -- an admin is here! lets see if they chat a command!
       message = string.lower(message)
 		
 	local splitString = message:split(" ")
 	local slashCommand = splitString[1]
 	local cmd = slashCommand:split(prefix)
 	local cmdName = cmd[2]
 		
 	if commands[cmdName] then
 		local arguments = {}
 			
 		for i = 2, #splitString, 1 do
 			table.insert(arguments, splitString[i])
 		end
 			
 		commands[cmdName](player,arguments)
 	end

    end
 end)
end)

Right, lets make a command. Right under our isAdmin() function.

commands.tp = function(sender,args)
    print(sender.Name.." fired the teleport command!")

   local playerToTeleportName = args[1]
	local playerToTeleportToName = args[2]
	
	if playerToTeleportName and playerToTeleportToName then
		local plrToTp = findPlayer(playerToTeleportName,sender)
		local plrToTpTo = findPlayer(playerToTeleportToName,sender)
		
		if plrToTp and plrToTpTo then
			plrToTp.Character.HumanoidRootPart.CFrame = plrToTpTo.Character.HumanoidRootPart.CFrame
		end
	end
end

This is probably the most difficult part of the code to understand, so stick with me here!
commands.tp means that we just added a tp function to our table from earlier. Players can chat something like "/tp player1 player2" to teleport now!

We check to see if the arguments are given, and if they are, find the matching player. If they exist too, teleport them to each other. We check by using our findPlayer() function from earlier!

COMPLETED CODE:
local admins = {}
local commands = {}
local prefix = "/"

local function findPlayer(name,sender)
 for _,player in pairs(game.Players:GetPlayers()) do
 	if string.lower(name) == "me" then
 		return sender
 	elseif string.lower(player.Name) == name then
 		return player
 	end
 end
 
 return nil
end

local function isAdmin(player)
 for _,Admin in pairs(admins) do
 	if string.lower(Admin) == string.lower(player.Name) then
 		return true
 	end
 end
 
 return false
end

commands.tp = function(sender,args)
    print(sender.Name.." fired the teleport command!")

   local playerToTeleportName = args[1]
	local playerToTeleportToName = args[2]
	
	if playerToTeleportName and playerToTeleportToName then
		local plrToTp = findPlayer(playerToTeleportName,sender)
		local plrToTpTo = findPlayer(playerToTeleportToName,sender)
		
		if plrToTp and plrToTpTo then
			plrToTp.Character.HumanoidRootPart.CFrame = plrToTpTo.Character.HumanoidRootPart.CFrame
		end
	end
end

game.Players.PlayerAdded:Connect(function(player)
 player.Chatted:Connect(function(message)
    if isAdmin(player) then
       -- an admin is here! lets see if they chat a command!
       message = string.lower(message)
 		
 	local splitString = message:split(" ")
 	local slashCommand = splitString[1]
 	local cmd = slashCommand:split(prefix)
 	local cmdName = cmd[2]
 		
 	if commands[cmdName] then
 		local arguments = {}
 			
 		for i = 2, #splitString, 1 do
 			table.insert(arguments, splitString[i])
 		end
 			
 		commands[cmdName](player,arguments)
 	end

    end
 end)
end)
HOW TO ADD YOUR OWN COMMANDS OTHER THAN TP:

This tutorial will not cover how to script them, but I have set up how it will be done for you all :slight_smile:

We know how to make commands by doing:

commands.WhateverCommandNameHere = function(sender,args)
      -- do code
end

Just remember to make the command name lowercase or it will not work. Remember, sender is the person who chatted the command and args is the players and other stuff they need for the command. For example, args could look something like this if they did the teleport function:

{"SpacePuppy2","OtherPlayer"}

IF THERE IS ANYTHING WRONG WITH THE TUTORIAL / IT DOES NOT WORK LET ME KNOW. I MADE THIS OFF THE TOP OF MY HEAD :sweat_smile:

This code is very similar to @Alvin_Blox’s tutorial on admin commands, go check him out on YT! He makes awesome scripting tutorials that are probably easier to understand than this!

12 Likes

looks cool! this is a really great resource for people just starting out. it would be better to store admins using userids (so when users change their name you don’t have to update your code), and you made a typo (in the admins table it ended with a ) instead of }). otherwise, amazing!

2 Likes

Could you notify me of what step in my tutorial that was in? I will make sure to fix it immediately.

Edit, found it. Fixed.

1 Like

Nah bro ngl your tutorial is way better than one of Alvin_Blox’s and I am not exaggerating. I may get hated for this but his tutorials aren’t the best and he doesn’t use good scripting practises.

1 Like

I completely agree this tutorial was made very well!

1 Like

Some feedback on the tutorial

The checking system uses a redundant if statement, you should be able to put it in front of the for loop instead of inside of it. As it will just be checked over and over again which is wasteful

local function findPlayer(name,sender)
    -- by putting it out in front, it doesn't get checked for every player
    if string.lower(name) == "me" then 
		return sender
    end
	for _,player in pairs(game.Players:GetPlayers()) do
		if string.lower(player.Name) == name then
			return player
		end
	end
	
	return nil
end

Additionally this should be edited to use string.find() so that people don’t need to put in the entire username, it’s not that hard of a fix either

if string.find(string.lower(player.Name), "^"..name) then 
-- the ^ is a special character that means that it checks only the front of the string.

Having this additional arguments table isn’t needed, you can just remove the first argument (the command) from the splitString list and send that.

local arguments = table.remove(splitString, 1)

Regarding the teleport command, you should really add checks to make sure that the character humanoid root parts exist, but that’s not too important.


Other than that, not a bad super basic admin tutorial, would definitely look to add more stuff for groups and other options! :slight_smile:

Ah, well Im only an intermediate scripter. About the string.find() thing, I was going to try and figure out how to make it so you don’t have to type out their whole username but I could not figure out how. Thanks for the feedback :grinning_face_with_smiling_eyes:

How would I be able to make a /kick command?

Sorry for the revive!