Hey there developers!
Do you ever have trouble creating a warn system for your admin panels? Or would you like to make one but don’t know how to? This tutorial is perfect for you!
Today we will go through each and every step on How to create a warn system along with discord embeds (Webhooks).
This tutorial does not contain user permissions and the permissions given to certain players that can use the warn system yet. It will be added in the future for sure.
This tutorial is divided in different sections. Be sure to read every section carefully.
What is a warn system?
A warning system is an essential tool in admin panels. Suppose a player in your game attempts to break the rules but isn’t as severe. Instead of banning the person or kicking him from the game. You can warn that player through an admin Panel. On a certain amount of warns, the person shall be punished.
Attention!
- Do not share your webhook’s URL with anyone!
- If you are banned from your own game by accident, be sure to change the name of the BanDataStore!
If you have any issues, reply down below.
After this tutorial you will be able to
- Warn a player.
- Store player’s warns.
- Send a discord embed notifying you who was warned and with what reason.
- Script auto temporary ban after a certain amount of warns have been given to a player.
Tutorial
Be sure to understand the code first!
Important
Be sure to Publish your game. Go to your game settings, go to Security and enable Api Service and HTTP Requests!
Setting up our Webhook
-
The first step would be creating yourself a discord server.
-
Head on to the Server Settings of your server.
-
Then click Integrations
-
Click on Webhooks
-
If you haven’t already created a webhook. Then click New Webhook
-
Enter the Valid information. Your Webhook should have information like this.
-
Optional: You can change the webhook name to whatever you want, the Bot’s Profile Picture. You can also select any channel in your server you want the bot to send the embed in.
-
After you have completed creating your webhook. Click Save Changes. And then Copy your webhook’s URL by clicking Copy Webhook URL as we need it later!
Setting up Warning GUI
- Open Roblox Studio and head into your game.
- Insert a ScreenGui inside StarterGui and name it to whatever you want. I named it WarnSystem
- You will need a few essential things in it.
- Insert a Frame inside the ScreenGui that we created. Add a TextBox named PlayerName.
- Insert another TextBox inside the Frame and name it as Reason
- Last but not the least create a TextButton named WarnButton
- You can edit the GUI to your expectations.
- Mine looks something like this (I am bad at GUIs)
Creating Remote Events
- Insert a Remote Event inside the ReplicatedStorage and name it as Warn
Scripting our Warn System
Insert a LocalScript inside our WarnButton in the StarterGui and type out this code -
local usernameBox = script.Parent.Parent.PlayerName --getting our playername textbox
local reasonBox = script.Parent.Parent.Reason --getting our warn textbox
local remoteEvent = game:GetService("ReplicatedStorage").Warn
script.Parent.MouseButton1Click:Connect(function() --when our button is clicked
remoteEvent:FireServer(tostring(usernameBox.Text), tostring(reasonBox.Text)) --fires the server and passes player username and warn reason
end)
Now we insert a Server Script inside ServerScript Service named WarnHandler. You can choose any name you like.
Type this code inside it -
local WarnDataStore = game:GetService("DataStoreService"):GetDataStore("WarnDataStore") --setting up our datastore
local TempBanStore = game:GetService("DataStoreService"):GetDataStore("BanDataStore") --setting up our ban datastore.
local HttpsService = game:GetService("HttpService") --getting httpservice
local WebhookURL = "your webhook's url here" --url of our webhook that we copied some time ago
game:GetService("ReplicatedStorage").Warn.OnServerEvent:Connect(function(moderator, username, reason) --when event is fired. Moderator is the player that clicks the button
local Success, Result = pcall(function() --getting player's warn data using a pcall
return WarnDataStore:GetAsync(tostring(username));
end)
if Result then
local allWarns = Result.Warns --table of all warns the player has got
print(Result) --prints player warn data (optional)
if Result ~= nil then --checks if player has warn data
table.insert(allWarns, reason) --inserts the warn to the table
local Success, Error = pcall(function() --pcall that saves player's warn data
WarnDataStore:SetAsync(tostring(username),{Warns = allWarns})
end)
if Success then --if player warn data was stored
local embed = --setting up our embed
{
["content"] = "",
["embeds"] = {{
["title"] = "**Action**: Warn",
["description"] = "A player was warned in **Game name**",
["type"] = "rich",
["color"] = 15105570,
["fields"] = {
{
["name"] = "**Warned**",
["value"] = username,
["inline"] = false
},
{
["name"] = "**Reason**",
["value"] = reason,
["inline"] = false
},
{
["name"] = "**Number of Warns**",
["value"] = #allWarns,
["inline"] = false
},
{
["name"] = "**Moderator**",
["value"] = moderator.Name,
["inline"] = false
}
},
["footer"] = {
["text"] = "Log Type: Manual Warn", }
}}
}
local embed = HttpsService:JSONEncode(embed)
HttpsService:PostAsync(WebhookURL, embed) --sends the embed to your discord server's channel
else --if player warn data could not be saved
print(Error)
end
else --if player warn data didnt exist earlier
local Success, Error = pcall(function() --creating and storing player warn data using a pcall
WarnDataStore:SetAsync(tostring(username),{Warns = {reason}})
end)
if not Success then --if player warn data failed to save
print(Error)
end
local embed = --setting up our embed
{
["content"] = "",
["embeds"] = {{
["title"] = "**Action**: Warn",
["description"] = "A player was warned in **Game name**",
["type"] = "rich",
["color"] = 15105570,
["fields"] = {
{
["name"] = "**Warned**",
["value"] = username,
["inline"] = false
},
{
["name"] = "**Reason**",
["value"] = reason,
["inline"] = false
},
{
["name"] = "**Moderator**",
["value"] = moderator.Name,
["inline"] = false
}
},
["footer"] = {
["text"] = "Log Type: Manual Warn", }
}}
}
local embed = HttpsService:JSONEncode(embed)
HttpsService:PostAsync(WebhookURL, embed) --sending our embed to the discord channel
end
end
end)
Now we have a Warn System with a datastore complete!
Scripting our Automatic Ban System and Moderator Permissions
Now we need a BanDataStore to store player ban data. At a certain amount of warns the player shall be banned from the game for 1 whole day (24 Hours). Here i take the amount of warns to be a multiple of 3. Meaning every 3rd warn a player gets he/she will be banned from the game for 1 whole day. Example: I get 3 warns. I get banned for 1 day. Then i get total 6 warns, again i get banned for 1 day.
We will now make a few edits inside our WarnHandler Script. We will also edit the permissions of the players that can use the warn system aka the moderators
We add these lines of code to our already existing code -
if #allWarns%3 == 0 then --checks if player has the correct amount of warns
local Success, result = pcall(function() --getting player ban data
return TempBanStore:GetAsync(tostring(username, "TempBan"));
end)
if not Success then --if player data could not be loaded
print("Player ban data could not be loaded.")
end
if Success then
print(result) --prints the player's ban data (optional)
if result ~= nil then --checks if player is already banned
print("The user is already banned")
else --if not then
game.Players[username]:Kick("You have been temporarily Banned for 1 day"); --kicks the player
local Success, Error = pcall(function() --saving player ban data for 1 day
TempBanStore:SetAsync(tostring(username), {BanStart = os.time(), BanDuration = 86400, BanReason = "Multiple Warns"});
end)
local embed = --setting up our embed
{
["content"] = "",
["embeds"] = {{
["title"] = "**Action**: Temp Ban",
["description"] = "A player was temporarily Banned from **Game name**",
["type"] = "rich",
["color"] = 15158332,
["fields"] = {
{
["name"] = "**Banned**",
["value"] = username,
["inline"] = false
},
{
["name"] = "**Duration**",
["value"] = "1 day",
["inline"] = false
},
{
["name"] = "**Reason**",
["value"] = "Multiple Warns",
["inline"] = false
},
{
["name"] = "**Moderator**",
["value"] = moderator.Name,
["inline"] = false
}
},
["footer"] = {
["text"] = "Log Type: Temporary Ban", }
}}
}
local embed = HttpsService:JSONEncode(embed)
HttpsService:PostAsync(WebhookURL, embed) --sends our embed to our discord server
end
end
end
Your final WarnHandler script should look like this -
local WarnDataStore = game:GetService("DataStoreService"):GetDataStore("WarnDataStore") --setting up our datastore
local TempBanStore = game:GetService("DataStoreService"):GetDataStore("BanDataStore") --setting up our ban datastore.
local HttpsService = game:GetService("HttpService") --getting httpservice
local WebhookURL = "your webhook's url here" --url of our webhook that we copied some time ago
local moderators = {"player1", "jaipack17", "player3", "player4"} --here we write our moderators' names
game:GetService("ReplicatedStorage").Warn.OnServerEvent:Connect(function(moderator, username, reason) --when event is fired. Moderator is the player that clicks the button
local check = table.find(moderators, tostring(moderator))
print(moderator)
if check == nil then
print("Player is not a moderator")
return
end
local Success, Result = pcall(function() --getting player's warn data using a pcall
return WarnDataStore:GetAsync(tostring(username), "WarnData");
end)
if Result then
local allWarns = Result.Warns --table of all warns the player has got
print(Result) --prints player warn data (optional)
if Result ~= nil then --checks if player has warn data
table.insert(allWarns, reason) --inserts the warn to the table
local Success, Error = pcall(function() --pcall that saves player's warn data
WarnDataStore:SetAsync(tostring(username),{Warns = allWarns})
end)
if Success then --if player warn data was stored
local embed = --setting up our embed
{
["content"] = "",
["embeds"] = {{
["title"] = "**Action**: Warn",
["description"] = "A player was warned in **Game name**",
["type"] = "rich",
["color"] = 15105570,
["fields"] = {
{
["name"] = "**Warned**",
["value"] = username,
["inline"] = false
},
{
["name"] = "**Reason**",
["value"] = reason,
["inline"] = false
},
{
["name"] = "**Number of Warns**",
["value"] = #allWarns,
["inline"] = false
},
{
["name"] = "**Moderator**",
["value"] = moderator.Name,
["inline"] = false
}
},
["footer"] = {
["text"] = "Log Type: Manual Warn", }
}}
}
local embed = HttpsService:JSONEncode(embed)
HttpsService:PostAsync(WebhookURL, embed) --sends the embed to your discord server's channel
if #allWarns%3 == 0 then --checks if player has the correct amount of warns
local Success, result = pcall(function() --getting player ban data
return TempBanStore:GetAsync(tostring(username, "TempBan"));
end)
if not Success then --if player data could not be loaded
print("Player ban data could not be loaded.")
end
if Success then
print(result) --prints the player's ban data (optional)
if result ~= nil then --checks if player is already banned
print("The user is already banned")
else --if not then
if game.Players:FindFirstChild(username) then
game.Players[username]:Kick("You have been temporarily Banned for 1 day"); --kicks the player
end
local Success, Error = pcall(function() --saving player ban data for 1 day
TempBanStore:SetAsync(tostring(username), {BanStart = os.time(), BanDuration = 86400, BanReason = "Multiple Warns"});
end)
local embed = --setting up our embed
{
["content"] = "",
["embeds"] = {{
["title"] = "**Action**: Temp Ban",
["description"] = "A player was temporarily Banned from **Game name**",
["type"] = "rich",
["color"] = 15158332,
["fields"] = {
{
["name"] = "**Banned**",
["value"] = username,
["inline"] = false
},
{
["name"] = "**Duration**",
["value"] = "1 day",
["inline"] = false
},
{
["name"] = "**Reason**",
["value"] = "Multiple Warns",
["inline"] = false
},
{
["name"] = "**Moderator**",
["value"] = moderator.Name,
["inline"] = false
}
},
["footer"] = {
["text"] = "Log Type: Temporary Ban", }
}}
}
local embed = HttpsService:JSONEncode(embed)
HttpsService:PostAsync(WebhookURL, embed) --sends our embed to our discord server
end
end
end
end
else --if player warn data could not be saved
print("Error while saving data")
end
else --if player warn data didnt exist earlier
local Success, Error = pcall(function() --creating and storing player warn data using a pcall
WarnDataStore:SetAsync(tostring(username),{Warns = {reason}})
end)
if not Success then --if player warn data failed to save
print(Error)
end
local embed = --setting up our embed
{
["content"] = "",
["embeds"] = {{
["title"] = "**Action**: Warn",
["description"] = "A player was warned in **Game name**",
["type"] = "rich",
["color"] = 15105570,
["fields"] = {
{
["name"] = "**Warned**",
["value"] = username,
["inline"] = false
},
{
["name"] = "**Reason**",
["value"] = reason,
["inline"] = false
},
{
["name"] = "**Moderator**",
["value"] = moderator.Name,
["inline"] = false
}
},
["footer"] = {
["text"] = "Log Type: Manual Warn", }
}}
}
local embed = HttpsService:JSONEncode(embed)
HttpsService:PostAsync(WebhookURL, embed) --sending our embed to the discord channel
end
end)
Now we have setup our ban datastore!
Scripting Automatic Kick on ban
We created the ban system in the last section. Now we need to kick the player from the game everytime the player joins the game while being banned.
Create a new Server Script inside ServerScriptService and name it as BanChecker. (You can name it whatever you want)
Type this code -
local TempBanStore = game:GetService("DataStoreService"):GetDataStore("BanDataStore") --getting our ban datastore.
local HttpsService = game:GetService("HttpService") --getting httpservice
local WebhookURL = "your webhook's url here" --url of our webhook
game.Players.PlayerAdded:Connect(function(Player) --when player is added
local Success, Result = pcall(function() --getting player ban data
return TempBanStore:GetAsync(tostring(Player.Name, "TempBan"));
end)
if Success then --if player data was loaded
if Result then
print(Result) --print the player ban data (optional)
if Result.BanStart ~= nil and Result.BanDuration ~= nil then --checks if player data is present. If yes then
if Result.BanStart + Result.BanDuration <= os.time() then --checks if player ban time is over (1 day)
print("User has been unbanned") --unbans the user if ban time is over
local embed = --setting up our embed
{
["content"] = "",
["embeds"] = {{
["title"] = "**Action**: Unbanned",
["description"] = "A player was Unbanned from **Game name**",
["type"] = "rich",
["color"] = 3066993,
["fields"] = {
{
["name"] = "**Unbanned**",
["value"] = Player.Name,
["inline"] = false
},
{
["name"] = "**Past Ban Reason**",
["value"] = Result.BanReason,
["inline"] = false
},
{
["name"] = "**Automatic Unban**",
["value"] = "Temporary Ban Time Over",
["inline"] = false
},
},
["footer"] = {
["text"] = "Log Type: Automatic Unban", }
}}
}
local embed = HttpsService:JSONEncode(embed)
HttpsService:PostAsync(WebhookURL, embed) --sends the embed to the discord server
TempBanStore:RemoveAsync(tostring(Player.Name)); --removes player ban data
else
Player:Kick("You have been Temporarily Banned") --if ban time is not over we kick the player
end
end
end
end
end)
Yay! Our warn system is complete! If you have any doubts, feedback, more information about the same be sure to reply down below!
Thanks!
Update
Warn system now has Moderator permissions. You can set the players that have access to the warn system.