Server-sided cooldowns to prevent exploits won't work, any suggestions?

To summarize, I’m creating a fighting game that uses client-sided hitboxes for good responsiveness, and run checks on the server to make sure exploiters don’t abuse this and change cooldowns, range and whatnot. The issue is, when I try to create the server cooldown, it doesn’t stop the actions inside the boolean. The range detection part of it works completely fine. Any suggestions or any other simple way? The data argument in the remote event only contains things like the hitbox position, and combo count by the way. (Included the whole script incase there’s something in the script affecting it.)

local remote = game:GetService('ReplicatedStorage').Remotes.Attacks.Sp.Click
local cooldownTable = {} --//List of server cooldowned players to prevent exploits!

remote.OnServerEvent:Connect(function(player, data, hit)
	if (not cooldownTable[player]) and (data.Position - hit.Parent.HumanoidRootPart.Position).magnitude < 7 and not player.Character:FindFirstChild('Stun') then --Preventing cooldown, stun, and range hackers.
		table.insert(cooldownTable, player)	
		delay(.4, function()
			cooldownTable[player] = nil	
		end)
		
		
		if hit.Parent:FindFirstChild('IFrame') then return end --Return ends
		
		if data.Combo < 4 then
			if not hit.Parent:FindFirstChild('Blocking') then
				hit.Parent.Humanoid:TakeDamage(2.5)
				local stun = Instance.new("BoolValue", hit.Parent)
				stun.Name = "Stun"
				if data.Combo == 1 then
					game.Debris:AddItem(stun, .45)
				elseif data.Combo == 2 then
					game.Debris:AddItem(stun, .4)
				elseif data.Combo > 2 then
					game.Debris:AddItem(stun, .35)
				end				
			else
				--//Blocking
			end
			
			local bv = Instance.new('BodyVelocity', hit.Parent.HumanoidRootPart)
			bv.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 15
			bv.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv, .2)
			local bv2 = Instance.new('BodyVelocity', player.Character.HumanoidRootPart)
			bv2.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 15
			bv2.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv2, .2)
		else			
			if not hit.Parent:FindFirstChild('Blocking') then
				hit.Parent.Humanoid:TakeDamage(5)				
			else
				--//Blocking
			end
			local bv = Instance.new('BodyVelocity', hit.Parent.HumanoidRootPart)
			bv.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 70
			bv.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv, .4)
			local bv2 = Instance.new('BodyVelocity', player.Character.HumanoidRootPart)
			bv2.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 15
			bv2.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv2, .2)
		end
	end--//CD CHECK END	
end)
1 Like

A debounce would be the correct method. The only thing is that you’re writing and reading using 2 separate “methods” for lack of a better word.

table.insert appends the value to the table giving the value a numerical index.
Indexing a table using brackets indexes the table with an index using an arbitrary type.

So, you’re checking if the debounce is false using the player as an index, but when you actually insert to the table you’re inserting using a numerical index.

So I’ll try breaking it down step by step:

cooldownTable now is {}
in connection: 
    check if table[player] is falsy (nil or false)
    insert player to the table; table now is { [1] = player }
    task.delay(.4, set cooldownTable[player] to nil, ultimately nothing changes, table now is still { [1] = player })

So what happens on the next event if the cooldown isn’t over?

in connection:
    table now is { [1] = player }
    so, check if table[player] is falsy, it is, so condition passes

To fix it, instead of doing table.insert(t, player), do t[player] = true, and then set t[player] to nil after .4 seconds. Or switch out t[player] with table.find(t, player). I think using t[player] = true is faster tho.

I tried doing both methods (table.find(cooldownTable, player), and cooldownTable[Player] = true and it still ended up not working. Pretty weird. Here’s my script at the moment: (Edited the cooldown bit since I discovered a security flaw with it, still works fine)

local remote = game:GetService('ReplicatedStorage').Remotes.Attacks.Sp.Click
local cooldownTable = {} --//List of server cooldowned players to prevent exploits!

remote.OnServerEvent:Connect(function(player, data, hit)
	if (not cooldownTable[player]) and (player.Character.HumanoidRootPart.CFrame * CFrame.new(0,0,-3).Position - hit.Parent.HumanoidRootPart.Position).magnitude < 7 and not player.Character:FindFirstChild('Stun') then --Preventing cooldown, stun, and range hackers.
		cooldownTable[player] = true
		delay(.4, function()
			cooldownTable[player] = nil	
		end)
		
		if hit.Parent:FindFirstChild('IFrame') then return end --Return ends
		
		if data.Combo < 4 then
			if not hit.Parent:FindFirstChild('Blocking') then
				hit.Parent.Humanoid:TakeDamage(2.5)
				local stun = Instance.new("BoolValue", hit.Parent)
				stun.Name = "Stun"
				if data.Combo == 1 then
					game.Debris:AddItem(stun, .45)
				elseif data.Combo == 2 then
					game.Debris:AddItem(stun, .4)
				elseif data.Combo > 2 then
					game.Debris:AddItem(stun, .35)
				end				
			else
				--//Blocking
			end
			
			local bv = Instance.new('BodyVelocity', hit.Parent.HumanoidRootPart)
			bv.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 15
			bv.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv, .2)
			local bv2 = Instance.new('BodyVelocity', player.Character.HumanoidRootPart)
			bv2.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 15
			bv2.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv2, .2)
		else			
			if not hit.Parent:FindFirstChild('Blocking') then
				hit.Parent.Humanoid:TakeDamage(5)				
			else
				--//Blocking
			end
			local bv = Instance.new('BodyVelocity', hit.Parent.HumanoidRootPart)
			bv.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 70
			bv.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv, .4)
			local bv2 = Instance.new('BodyVelocity', player.Character.HumanoidRootPart)
			bv2.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 15
			bv2.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv2, .2)
		end
	end--//Exploit Check End
end)

(I also forgot to add that sometimes the server cooldown rarely works, not all the time though. Also possible it’s my hitbox system acting up, which I highly doubt.)

Sorry for late response. It looks ok to me, are you sure it isn’t working? If you have poor internet connection sometimes that can cause synchronization issues on the client, but usually ping remains at a relatively constant rate so that might not be it.

I see you may have a minor issue though but I’m not too sure whether or not that’s causing it (or even if it’s unintended)

I think you might want to wrap these in parentheses (eg (player.Character.HumanoidRootPart.CFrame * CFrame.new(0,0,-3)).Position

Could you maybe try printing cooldownTable[player] and see? It might be because of your if statement condition but I’m really not too sure.

Why not use CollectionService?

local remote = game:GetService('ReplicatedStorage').Remotes.Attacks.Sp.Click
local __CS = game:GetService("CollectionService")
remote.OnServerEvent:Connect(function(player, data, hit)
	if not __CS:HasTag(player, "__INCOOLDOWN")and (player.Character.HumanoidRootPart.CFrame * CFrame.new(0,0,-3).Position - hit.Parent.HumanoidRootPart.Position).magnitude < 7 and not player.Character:FindFirstChild('Stun') then --Preventing cooldown, stun, and range hackers.
		__CS:AddTag(player, "__INCOOLDOWN")
                task.delay(0.4,function()
                      __CS:RemoveTag(player, "__INCOOLDOWN")
                end)
		if hit.Parent:FindFirstChild('IFrame') then return end --Return ends
		
		if data.Combo < 4 then
			if not hit.Parent:FindFirstChild('Blocking') then
				hit.Parent.Humanoid:TakeDamage(2.5)
				local stun = Instance.new("BoolValue", hit.Parent)
				stun.Name = "Stun"
				if data.Combo == 1 then
					game.Debris:AddItem(stun, .45)
				elseif data.Combo == 2 then
					game.Debris:AddItem(stun, .4)
				elseif data.Combo > 2 then
					game.Debris:AddItem(stun, .35)
				end				
			else
				--//Blocking
			end
			
			local bv = Instance.new('BodyVelocity', hit.Parent.HumanoidRootPart)
			bv.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 15
			bv.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv, .2)
			local bv2 = Instance.new('BodyVelocity', player.Character.HumanoidRootPart)
			bv2.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 15
			bv2.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv2, .2)
		else			
			if not hit.Parent:FindFirstChild('Blocking') then
				hit.Parent.Humanoid:TakeDamage(5)				
			else
				--//Blocking
			end
			local bv = Instance.new('BodyVelocity', hit.Parent.HumanoidRootPart)
			bv.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 70
			bv.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv, .4)
			local bv2 = Instance.new('BodyVelocity', player.Character.HumanoidRootPart)
			bv2.Velocity = player.Character.HumanoidRootPart.CFrame.LookVector * 15
			bv2.MaxForce = Vector3.new(99999,99999,99999)
			game.Debris:AddItem(bv2, .2)
		end
	end--//Exploit Check End
end)

This worked beautifully! I had no idea of this service’s existence. Good to know!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.