Here’s a simple, easy-to-use moderation system I built and want to share with the community. It has 4 main functions.
- Ban - Kicks the player every time they join
- Temporary Ban - Same thing as the ban but after a set time period they may rejoin again
- Unban - Allows the player to rejoin
- Kicking - Kicks the player
Script
-- Made by @bonejon
local DSS = game:GetService("DataStoreService")
local HttpService = game:GetService("HttpService")
local RS = game:GetService("ReplicatedStorage")
local PS = game:GetService("Players")
local banStorage = DSS:GetDataStore("Bans")
local banEvent = RS.Moderation:FindFirstChild("banEvent")
local unbanEvent = RS.Moderation:FindFirstChild("unbanEvent")
local kickEvent = RS.Moderation:FindFirstChild("kickEvent")
--Controls
local groupID = 0 -- Replace with groups ID
local adminRank = 255 -- 0 is not in group, 255 is owner
local adminIds = { -- Replace with any user's ID if you want them to have access
12345678,
12345678
}
-- Takes formatted duration and returns it in seconds
local function durationToUnixSeconds(duration)
local years = duration.years or 0
local months = duration.months or 0
local weeks = duration.weeks or 0
local days = duration.days or 0
local hours = duration.hours or 0
local minutes = duration.minutes or 0
local seconds = duration.seconds or 0
--1 month = 30 days and 1 year = 365 days
seconds = seconds + years * 365 * 24 * 60 * 60
seconds = seconds + months * 30 * 24 * 60 * 60
seconds = seconds + weeks * 7 * 24 * 60 * 60
seconds = seconds + days * 24 * 60 * 60
seconds = seconds + hours * 60 * 60
seconds = seconds + minutes * 60
return seconds
end
-- Banning logic
banEvent.OnServerEvent:Connect(function(player, oPlayerName, reason, banTime)
-- Get offender instance
local oPlayer = PS:FindFirstChild(oPlayerName)
-- Get players rank in set group
local groupRank = player:GetRankInGroup(groupID)
-- Check if player is on the admin list
local adminStatus = table.find(adminIds, player.UserId)
print(adminStatus)
-- If player is an admin then
if adminStatus or groupRank >= adminRank then
-- If we passed a time then its a temporary ban, otherwise its permanent
if banTime then
-- Add current unix time (seconds) and add it formatted ban duration in seconds to get unix time of a persons unban
local unbanTime = os.time() + durationToUnixSeconds(banTime)
-- Adds moderator name, the reason for the ban, and the unix time of the unban to the datastore under the UID of offender
banStorage:SetAsync(oPlayer.UserId, HttpService:JSONEncode({player.Name, reason, unbanTime}))
-- Kicks the offender and displays, reason, moderator banned by, formatted date of the unban
oPlayer:Kick("You have been banned for " .. reason .. ". You were banned by " .. player.Name .. ". You will be unbanned on " .. os.date("%Y/%m/%d %H:%M", unbanTime) .. ".")
else
-- Adds the moderator name, the reason for the ban, no time because its permanent, to the datastore under the UID of the offender
banStorage:SetAsync(oPlayer.UserId, HttpService:JSONEncode({player.Name, reason}))
-- Kicks the offender and displays, reason, and moderator banned by
oPlayer:Kick("You have been banned permanently for " .. reason .. ". You were banned by " .. player.Name .. ".")
end
end
end)
-- Unbanning logic
unbanEvent.OnServerEvent:Connect(function(player, oPlayerUID)
-- Get players rank in set group
local groupRank = player:GetRankInGroup(groupID)
-- Check if player is on the admin list
local adminStatus = table.find(adminIds, player.UserId)
print(adminStatus)
-- If player is an admin then
if adminStatus or groupRank >= adminRank then
-- Removes the datastore entry with the offenders User ID
banStorage:RemoveAsync(oPlayerUID)
end
end)
-- Kicking logic
kickEvent.OnServerEvent:Connect(function(player, oPlayerName, reason)
-- Get offender instance
local oPlayer = PS:FindFirstChild(oPlayerName)
-- Get players rank in set group
local groupRank = player:GetRankInGroup(groupID)
-- Check if player is on the admin list
local adminStatus = table.find(adminIds, player.UserId)
print(adminStatus)
-- If player is an admin then
if adminStatus or groupRank >= adminRank then
-- Kicks the offender and displays reason and moderator kicked by
oPlayer:Kick("You have been kicked for " .. reason .. ". You have been kicked by " .. player.Name .. ".")
end
end)
-- Kick banned players logic
PS.PlayerAdded:Connect(function(oPlayer)
-- Get all data from datastore about player
local success, rawData = pcall(function()
return banStorage:GetAsync(oPlayer.UserId)
end)
-- If data was found then decode and kick
if success and rawData then
local data = HttpService:JSONDecode(rawData)
-- Seperate data into easy use variables
local modName = data[1]
local reason = data[2]
local unbanTime = data[3]
-- If there is unbanTime then its temporary
if unbanTime then
-- If unix time (seconds) is greater than unban time (seconds) then unban, otherwise kick
if os.time() > unbanTime then
-- Remove offender from datastore
banStorage:RemoveAsync(oPlayer.UserId)
else
-- Kick em because there is still time left on their ban
oPlayer:Kick("You have been banned for " .. reason .. ". You were banned by " .. modName .. ". You will be unbanned on " .. os.date("%Y/%m/%d %H:%M", unbanTime) .. ".")
end
else
-- Kick em because it is a permanent ban
oPlayer:Kick("You have been banned permanently for " .. reason .. ". You were banned by " .. modName .. ".")
end
end
end)
Set Up
This all gets called with 3 remoteEvent’s in a folder in ReplicatedStorage and the script sits in ServerScriptStorage.
Inside the script there is a two settings you need to change by the top of the script
--Controls
local groupID = 0 -- Replace with groups ID
local adminRank = 255 -- 0 is not in group, 255 is owner
local adminIds = { -- Replace with any user's ID if you want them to have access
12345678,
12345678
}
These are who can call these functions, if you have a group with admins then you can add them. If you do not have a group, or have people who you want to admin your game but are not in the group then you can add them.
GroupID is found by heading to your group and copying the group id from the url and pasting into groupID (See Picture.)
To find the rank of the admin you need to go to, the three dots and selecting Configure Community (See Picture.)
Then click on roles (See Picture.)
Then click on the lowest role you want to have admin access (See Picture.)
Then copy rank and paste it into adminRank (See Picture.)
To set up individual users as admins, first go to the users profile (See Picture.)
Then copy and paste their user id into the adminIds array, the more the merrier (See Picture.)
Any words wrapped in is a variable. A double dash – is an explanation. You also can only :FireServer() in a localscript, this was designed for UI use but all the code will work without the remoteEvent with some tinkering.
Calling Ban:
local banEvent = game.ReplicatedStorage.Moderation:WaitForChild("banEvent")
banEvent:FireServer( [OffendingPlayersName] , [Reason] )
Calling Temporary Ban:
local banEvent = game.ReplicatedStorage.Moderation:WaitForChild("banEvent")
local time = {
years = 0,
months = 0,
weeks = 0,
days = 0,
hours = 0,
minutes = 0,
seconds = 0
}
banEvent:FireServer( [OffendingPlayersName] , [Reason] , time) --You may replace time with an array like {minutes = 1, seconds = 30}
Calling Unban:
local unbanEvent = game.ReplicatedStorage.Moderation:WaitForChild("unbanEvent")
unbanEvent:FireServer( [OffendingPlayersUserId] )
Calling A Kick:
local kickEvent = game.ReplicatedStorage.Moderation:WaitForChild("kickEvent")
kickEvent:FireServer( [OffendingPlayersName], [Reason] )
Video of system working.
If you find any issues please comment and I will try and fix it.










