I need help debugging a ban system that relies on a datastore + improving it

Before I get started, the way to ban players in the game I’m trying to make is through a GUI. Yes, you heard me, a GUI. To ban players, A player must type in a TextBox, then press a button in order to ban a player, which a remoteEvent with the text inside the textbox is fired towards a ServerScript. After validating that the player is a confirmed admin, the script will attempt to find the player in the server, then update the datastore to ensure the player can never join back again while also kicking the player from the game.

Here are my scripts. Some of them may be heavily shortened.

Button Script
-- VARIABLES

local RS = game:GetService("ReplicatedStorage")
local Player = game.Players.LocalPlayer
local SGUI = script.Parent.Parent.Parent
local Button = SGUI.ScrollingFrame:WaitForChild("BanPlayer")
local banEvent = RS.BanEvent
local debounce = false
local PGUI = Player:WaitForChild("PlayerGui")

--EVENT

Button.MouseButton1Click:Connect(function()
	local text = PGUI.AdminPanel.ScrollingFrame.BanPlayer
	if debounce == false then
		debounce = true
		print("SUCCESS")
		banEvent:FireServer(text.Text)
		task.wait(0.25)
		debounce = false
	end
end)
Admin Panel
--VARIABLES

local rS = game:GetService("ReplicatedStorage")
local SSS = game:GetService("ServerScriptService")
local SG = game:GetService("StarterGui")
local DS = game:GetService("DataStoreService")
local Players = game:GetService("Players")

local BanStore = DS:GetDataStore("BanStore")

local BanEvent = rS.BanEvent

--BANNING PLAYERS
BanEvent.OnServerEvent:Connect(function(Player, target)
	print(Player.Name)
	print(Player.UserId)
	print(target)
	if PanelWhitelist[Player.UserId] then
		print("SUCCESS")
		for i, player in pairs (Players:GetPlayers()) do
			if player.UserId == target then
				BanStore:SetAsync(player.UserId, true)
				player:Kick("???")			
			end
		end
	elseif not PanelWhitelist[Player.UserId] then
		print("SUCCEEDED")
		Player:Kick("NICE EXPLOITS.")
	end
end)
Server Script for banning players that attempt to join again
local DataStore = game:GetService("DataStoreService")
local module = require(script.ModuleScript)
local Players = game:GetService("Players")
local BanStore = DataStore:GetDataStore("BanStore")

function banned(Player)
	Player:Kick("Permanently Banned!")
end

game.Players.PlayerAdded:Connect(function(player)
	local BanData = BanStore:GetAsync(player.UserId)
	
	if BanData then
		banned(player)
	end
end)

The main problem currently lies in the Admin Panel script. Although the values do pass, the player (target) in the adminpanel script as the 2nd variable for the function does not seem to be banning the player according to their userid. Even though I have correctly entered the player’s UserId, the player isn’t getting kicked. It’s not the DataStore causing the problem, I have commented it out when I was testing the ban and I do not know what’s the problem.

In addition, I have a possible worry about the way of saving the data being unreliable. SetAsync is known to not care about data at all and overwrite everything in it’s path, compared to UpdateAsync. However, I have read what SetAsync does, which sets a value, but I have huge amounts of confusion revolving around DataStore, as it is something I have not yet learned and is challenging to figure out, especially when making a DataStore script for the first time without knowing what to do (Infact, I’ve had to use a YouTube video that has a ban system tutorial for the code for the third one and 2nd one however I have a few doubts about the code due to it’s reliability and including that I have no knowledge of how a DataStore works).

I do not know if it’s the most efficient method. Thus, I’m asking for help. I’m new to DataStores, but passing values? Not so much, although I could get better. That’s why I’m asking for help. I haven’t been able to fix the problem and I do not know much about DataStores, which is one of my hardest challenges I have yet to learn and use. If anyone would like to help, please do!

4 Likes

I believe datastores are one of the only ways to ban people right now, so I wouldn’t say it is an inefficient method. Also, Roblox should be releasing a ban API sometime in the near future.

Four things:

  1. Try using tonumber() when comparing the player’s UserId to the target value
    if player.UserId == tonumber(target) then

  2. Change your joining script to this. While the next two scripts probably won’t solve your original issue, you should still add a pcall in case the script throws an error later on.

game.Players.PlayerAdded:Connect(function(player)
	local BanData
	local success, errorm = pcall(function()
		BanData = BanStore:GetAsync(player.UserId)
	end)
	if not success then
		warn("Unable to load ban data for player "..player.Name..". Error message: "..errorm)
	else
		if BanData then
			banned(player)
		end
	end
end)
  1. Add a pcall to your save script
if player.UserId == target then
	local success, errorm = pcall(function()
		BanStore:SetAsync(player.UserId, true)
	end)
	if success then
		player:Kick("???")
	else
		warn("Error with saving ban data, error message: "..errorm)
	end
end
  1. If you want to ban a player with their username instead of their UserId, you can do something like this:
BanEvent.OnServerEvent:Connect(function(Player, username)
	print(Player.Name)
	print(Player.UserId)
	local target = Players:GetUserIdFromNameAsync(username)
	if PanelWhitelist[Player.UserId] then
		print("SUCCESS")
		for i, player in pairs (Players:GetPlayers()) do
			if player.UserId == target then
				local success, errorm = pcall(function()
					BanStore:SetAsync(player.UserId, true)
				end)
				if success then
					player:Kick("???")
				else
					warn("Error with saving ban data, error message: "..errorm)
				end	
			end
		end
	elseif not PanelWhitelist[Player.UserId] then
		print("SUCCEEDED")
		Player:Kick("NICE EXPLOITS.")
	end
end)

Sorry if I missed something in your original post

3 Likes

There was one thing that was missing, and that’s the player not being kicked after the DataStore value being saved. When I input a Player’s username and then click on the button to ban a player, the player doesn’t seem to get kicked at all initially even with both scripts (Although I haven’t been able to test the script you sent of getting the player’s username and then getting the userId of the player, which is something I didn’t know you could do on Roblox with something simple as GetUserIdFromNameAsync). That’s the only problem I haven’t managed to debug.

4 Likes

Are there any error messages?​​​​​​​​​

2 Likes

There are no error messages, however I am testing the ban system through Roblox Studio’s built in server test where you can set up 2 players and a local server.

2 Likes

Maybe try it in game. The player:Kick() line looks fine, so I don’t really know why that is happening.

3 Likes

I’ve tried it ingame. I’m seeing the prints, but not the player getting banned. I’ve also somewhat changed the target variable to this.

local target
	local success1, err = pcall(function()
		target = Players:GetUserIdFromNameAsync(username)
	end)

If I’m being honest, would this break the script or still make it run?

3 Likes

That should be fine. Also, can you tell me which print statements you are seeing?

1 Like

All I’m seeing is the prints before print("SUCCESS") on the 2nd condition. I’ve somewhat swapped the code.

BanEvent.OnServerEvent:Connect(function(Player, username)
	print(Player.Name)
	print(Player.UserId)
	local target
	local success1, err = pcall(function()
		target = Players:GetUserIdFromNameAsync(username)
	end)
	if success1 then
		if PanelWhitelist[Player.UserId] then
			print("SUCCESS")
			for i, player in pairs (Players:GetPlayers()) do
				if player.UserId == target then
					local success, errorm = pcall(function()
						BanStore:SetAsync(player.UserId, true)
					end)
					if success then
						player:Kick("???")
					else
						warn("Error with saving ban data, error message: "..errorm)
					end	
				end
			end
		elseif not PanelWhitelist[Player.UserId] then
			print("SUCCEEDED")
			Player:Kick("NICE EXPLOITS.")
		end
	end
end)

The only difference is that there is if success1 then.

1 Like

Try this, I added a few more print statements

for i, player in pairs (Players:GetPlayers()) do
	if player.UserId == target then
		print("Player found")
		local success, errorm = pcall(function()
			BanStore:SetAsync(player.UserId, true)
		end)
		if success then
			print("Data saved")
			player:Kick("???")
			print("Kicked player")
		else
			warn("Error with saving ban data, error message: "..errorm)
		end	
	end
end
1 Like

Same thing still happened, I’ve entered a player’s username, and they didn’t get kicked/banned.

1 Like

What messages printed to the output? I am trying to see where the problem is happening.

Also, are you sure you are entering the right UserId? If I remember correctly, the UserIds in the test version of Roblox studio are -1, -2 -3, and -4.

1 Like

Currently, only these 2 prints.

print(Player.Name)
print(Player.UserId)

There are no error messages being printed in the output. I’m assuming it’s the pcall function I added after these 2 prints.

1 Like
if success1 then
		if PanelWhitelist[Player.UserId] then
			print("SUCCESS")
			for i, player in pairs (Players:GetPlayers()) do
				if player.UserId == target then
					local success, errorm = pcall(function()
						BanStore:SetAsync(player.UserId, true)
					end)
					if success then
						player:Kick("???")
					else
						warn("Error with saving ban data, error message: "..errorm)
					end	
				end
			end
		elseif not PanelWhitelist[Player.UserId] then
			print("SUCCEEDED")
			Player:Kick("NICE EXPLOITS.")
		end
	end
else
    warn(err)
end)

See if it prints any warnings for the first pcall

1 Like

Alright so I’ve got this error in studio,

Players:GetUserIdFromNameAsync() failed: Unknown user

Does that mean the script works or do I have to continue testing ingame?

2 Likes

Try testing it in game. ​​​​​​​​​​​​​​​​​​​​​​​​​​​​​I believe it is because :GetUserIdFromNameAsyc() gets the UserId of anyone on the Roblox website, not just the game.

Here is a function if you only want to sort through the UserIds in the server:

local function GetUserId(Username: string)
  for _, v in pairs(Players:GetPlayers()) do
    if v.Name == Username then
      return v.UserId
    end
  return nil
end

Same thing happened, the first pcall didn’t pass even after typing in another user’s name correctly. Also tried the UserId, although the function was oriented for player usernames.

How can I implement that function in?

BanEvent.OnServerEvent:Connect(function(Player, username)
	print(Player.Name)
	print(Player.UserId)
	local target = GetUserId(username)
	if taget == nil then
		warn("UserId not found!")
		return
	end
	if PanelWhitelist[Player.UserId] then
		print("SUCCESS")
		for i, player in pairs (Players:GetPlayers()) do
			if player.UserId == target then
				local success, errorm = pcall(function()
					BanStore:SetAsync(player.UserId, true)
				end)
				if success then
					player:Kick("???")
				else
					warn("Error with saving ban data, error message: "..errorm)
				end	
			end
		end
	elseif not PanelWhitelist[Player.UserId] then
		print("SUCCEEDED")
		Player:Kick("NICE EXPLOITS.")
	end
end)

Edit: Forgot to remove the if statement for success1

Tried it again, but it kept printing that the target was “nil”.

Print the username variable and see what it is equal to. I don’t really see what else the issue could be.