Help making a temp ban system

My bad, I just forgot to hookup the “CharacterAdded” event to the “onCharacterAdded” function.

player.CharacterAdded:Connect(onCharacterAdded)

Here’s the full script with that change implemented (it works now).

local dataModel = game
local dataStoreService = dataModel:GetService("DataStoreService")
local dataStore = dataStoreService:GetDataStore("DataStore")
local players = dataModel:GetService("Players")

local kickedPlayers = {}
local protectedCall = pcall

local function onPlayerAdded(player)
	local function onCharacterAdded(character)
		local function onHumanoidDied()
			table.insert(kickedPlayers, player.UserId)

			local success, result = protectedCall(function()
				dataStore:SetAsync(player.UserId, tick()) --"true" indicates dead.
			end)

			if success then
				print(result)
			else
				warn(result)
			end

			player:Kick("You have died!")
		end

		local humanoid = character:WaitForChild("Humanoid")
		humanoid.Died:Connect(onHumanoidDied)
	end
	
	player.CharacterAdded:Connect(onCharacterAdded)
	
	if table.find(kickedPlayers, player.UserId) then
		player:Kick("You have already died in this server!")
	end

	local success, result = protectedCall(function()
		return dataStore:GetAsync(player.UserId)
	end)

	if success then
		if result then
			if tick() - result <= 86400 then --1 day.
				player:Kick("You have already died in another server! Please rejoin in "..math.round((86400)-(tick() - result)).." seconds.")
			else
				local success, result = protectedCall(function()
					return dataStore:RemoveAsync(player.UserId)
				end)
			end
		end
	else
		warn(result)
	end
end

players.PlayerAdded:Connect(onPlayerAdded)

Wonderful! Thank you so much, is there a way to unban myself? (for the purpose of testing :joy:)

local dataModel = game
local dataStoreService = dataModel:GetService("DataStoreService")
local dataStore = dataStoreService:GetDataStore("DataStore")
local players = dataModel:GetService("Players")

local whiteListed = {1, 2, 3} --Add IDs of whitelisted players here.
local kickedPlayers = {}
local protectedCall = pcall

local function onPlayerAdded(player)
	local function onCharacterAdded(character)
		local function onHumanoidDied()			
			table.insert(kickedPlayers, player.UserId)

			local success, result = protectedCall(function()
				dataStore:SetAsync(player.UserId, tick()) --"tick" records time.
			end)

			if success then
				print(result)
			else
				warn(result)
			end

			player:Kick("You have died!")
		end

		local humanoid = character:WaitForChild("Humanoid")
		humanoid.Died:Connect(onHumanoidDied)
	end
	player.CharacterAdded:Connect(onCharacterAdded)
	
	if table.find(whiteListed, player.UserId) then
		if table.find(kickedPlayers, player.UserId) then
			table.remove(kickedPlayers, table.find(kickedPlayers, player.UserId))
		end
		
		local success, result = protectedCall(function()
			return dataStore:RemoveAsync(player.UserId)
		end)

		if success then
			print(result)
		else
			warn(result)
		end
	end
	
	if table.find(kickedPlayers, player.UserId) then
		player:Kick("You have already died in this server!")
	end

	local success, result = protectedCall(function()
		return dataStore:GetAsync(player.UserId)
	end)

	if success then
		if result then
			if tick() - result <= 86400 then --1 day.
				player:Kick("You have already died in another server! Please rejoin in "..math.round((86400)-(tick() - result)).." seconds.")
			else
				local success, result = protectedCall(function()
					return dataStore:RemoveAsync(player.UserId)
				end)
			end
		end
	else
		warn(result)
	end
end

players.PlayerAdded:Connect(onPlayerAdded)

Here you go, I’ve added a whitelist to the top of the script.

local dataModel = game
local dataStoreService = dataModel:GetService("DataStoreService")
local dataStore = dataStoreService:GetDataStore("DataStore")
local players = dataModel:GetService("Players")

local whiteListed = {1, 2, 3} --Add IDs of whitelisted players here.
local kickedPlayers = {}
local protectedCall = pcall

local function onPlayerAdded(player)
	local function onCharacterAdded(character)
		local function onHumanoidDied()			
			table.insert(kickedPlayers, player.UserId)

			local success, result = protectedCall(function()
				dataStore:SetAsync(player.UserId, tick()) --"tick" records time.
			end)

			if success then
				print(result)
			else
				warn(result)
			end

			player:Kick("You have died!")
		end

		local humanoid = character:WaitForChild("Humanoid")
		humanoid.Died:Connect(onHumanoidDied)
	end
	player.CharacterAdded:Connect(onCharacterAdded)
	
	if table.find(kickedPlayers, player.UserId) then
		if not table.find(whiteListed, player.UserId) then
			player:Kick("You have already died in this server!")
		end
	end

	local success, result = protectedCall(function()
		return dataStore:GetAsync(player.UserId)
	end)

	if success then
		if result then
			if tick() - result <= 86400 then --1 day.
				if not table.find(whiteListed, player.UserId) then
					player:Kick("You have already died in another server! Please rejoin in "..math.round((86400)-(tick() - result)).." seconds.")
				end
			else
				local success, result = protectedCall(function()
					return dataStore:RemoveAsync(player.UserId)
				end)
			end
		end
	else
		warn(result)
	end
end

players.PlayerAdded:Connect(onPlayerAdded)

Similar script with a slightly different implementation (I prefer this approach).

table.method is O(n) because each time we run a function or insert anything it shifts the memory over.

Using a Hash would be the smartest thing to do. With that you can use the same logic you just displayed.

Fortunately we’re not working with arrays which contain thousands of entries so the difference is negligible.

I would disagree, front page games get heavy player counts. This system should be built to scale. The logic that we shouldn’t write code effectively the first time is what separates good developers from bad ones.

The tables are unique and restricted to a single server script (it isn’t a table shared by all active server instances).

I’ve performed bench-marking tests on indexing dictionaries versus the table library functions and even with thousands and thousands of entries the difference is minuscule (a fraction of a second at most).

Alright, last thing. (thanks for sticking around with me)

How can I make this activate when a RemoteEvent is fired? Rather than when the player dies.

local rem = game:GetService("ReplicatedStorage"):WaitForChild("RemoteEvent")
rem.OnServerEvent:Connect(onPlayerAdded)

The code you presented does not need to have any of the functionality aside from the whitelist information. I cant fathom why there is a kicked table as that data is already stored in a data store. It would be logical to use an array if there was a problem setting data store keys, but because each key is unique to the player, that logic doesn’t make sense.

Using the data store you already set the ban time, you can use a queue to check the data store for the information if requests are the issue. But because not many people will be banned, roblox default request limit wont cause any problems for checking the time. Therefore, we can completely remove the kicked table. Not to mention by using what your using you turned the already O(n) into O(n^2) which is exponentially slower.

As for being off topic, this conversation would help the OP understand what not to do. You can argue otherwise, however, its important to understand the difference between good and bad code. Some folks go a while without understanding the difference thus interfering with their development careers.

local dataModel = game
local dataStoreService = dataModel:GetService("DataStoreService")
local dataStore = dataStoreService:GetDataStore("DataStore")
local players = dataModel:GetService("Players")

local whiteListed = {1, 2, 3} --Add IDs of whitelisted players here.
local protectedCall = pcall

local function onPlayerAdded(player)
	local function onCharacterAdded(character)
		local function onHumanoidDied()			
			local success, result = protectedCall(function()
				dataStore:SetAsync(player.UserId, tick()) --"tick" records time.
			end)

			if success then
				print(result)
			else
				warn(result)
			end

			task.wait(players.RespawnTime)
			player:Kick("You have died!")
		end

		local humanoid = character:WaitForChild("Humanoid")
		humanoid.Died:Connect(onHumanoidDied)
	end
	player.CharacterAdded:Connect(onCharacterAdded)
	local success, result = protectedCall(function()
		return dataStore:GetAsync(player.UserId)
	end)

	if success then
		if result then
			if tick() - result <= 86400 then --1 day.
				if not table.find(whiteListed, player.UserId) then
					player:Kick("You have already died in another server! Please rejoin in "..math.round((86400)-(tick() - result)).." seconds.")
				end
			else
				local success, result = protectedCall(function()
					return dataStore:RemoveAsync(player.UserId)
				end)
			end
		end
	else
		warn(result)
	end
end

players.PlayerAdded:Connect(onPlayerAdded)

Just posting it here as well.

2 Likes