Antiexploit Help

Alright so I am trying to make an antiexploit system for my game. Before this, I was handling it on the client which I realized is a horrible idea, so today I managed to make it work on the server, but the issue was that if the player reset, it wouldn’t detect the exploits anymore. I tried to make it work after they reset but now it doesn’t detect the exploits at all. This is my current code. Sorry if it’s a pain to read.

local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
     Player = player
  local Connection
  local Humanoid
  local Character = player.Character or player.CharacterAdded:Wait()
while true do
	wait(.5)

  Player.CharacterAdded:Connect(function(character)
    Character = character
    Humanoid = character:WaitForChild("Humanoid")
    
    Connection = Humanoid.StateChanged:Connect(checkstate)
  end)
end
  me = Character:WaitForChild("Humanoid")
  
end)
		

TestCounter = 0
lastTime = 0

DataStoreService = game:GetService("DataStoreService")
BanStore = DataStoreService:GetDataStore("6Hbg$%HN")
local userinfo = BanStore:GetAsync(Player.UserId)
	if userinfo == "nil" then
		return
	elseif userinfo then
		Player:kick("\n Fruitose Anti-Exploit \n  \n You have been banned for using "..userinfo.." exploits. \n  \n You may appeal this ban in our discord server. \n  \n If you believe that this is a mistake, please contact a developer.")
	end

function checkstate(state)
	
	
	if state == Enum.HumanoidStateType.Seated then
		if lastTime > os.time() - 1 then
			TestCounter = TestCounter + 1
			
			if TestCounter > 2 then

				wait(1)
		    
		Player:Kick("You have been caught using infinite jump!")
				BanStore:SetAsync(Player.UserId, "infinite jump")
			end
		else
			lastTime = os.time()
			TestCounter = 0
		end
	end
	
	
	if state == Enum.HumanoidStateType.Flying then
		
		wait(1)
	
		Player:Kick("\n Fruitose Anti Exploit \n You have been kicked \n Reason: Added body velocity (Flying)")
		BanStore:SetAsync(Player.UserId, "fly")
	end
	
	if state == Enum.HumanoidStateType.StrafingNoPhysics then
		
		wait(1)
	
		Player:Kick("\n Fruitose Anti Exploit \n You have been banned. \n Reason: Disallowed state change (Noclip)\n You may appeal this ban in our discord server")
		BanStore:SetAsync(Player.UserId, "noclip")
	end
	
	if me.WalkSpeed > 18 then
		
		wait(1)
	
		Player:Kick("\n Fruitose Anti Exploit \n You have been kicked \n Reason: Walkspeed change detetcted (Speed Exploits)")
			BanStore:SetAsync(Player.UserId, "walkspeed")	
		
	end
	if me.JumpPower > 50 then
		
		wait(1)
	
		Player:Kick("\n Fruitose Anti Exploit \n You have been kicked \n Reason: Jumppower change detetcted (Jump exploits)")
			BanStore:SetAsync(Player.UserId, "jumppower")	
	end
	
end

me.StateChanged:Connect(checkstate)

Any help would be appreciated. (If you find any vulnerabilities, please feel free to point those out)

When a rogue client changes their humanoid’s WalkSpeed or JumpPower property, or anything that changes the movement of their player, it will not replicate the directly property change, but instead will replicate the position of the player.

You will have to use a different way to detect walkspeed hacks. One easy way is to check how fast someone’s body is moving (Velocity). Another would be to see how far they moved within 1 second. I would NOT BAN for movement based exploits because they’re volatile and can backfire and lead to wrong detentions.

1 Like

Hm. The walkspeed was working before. This issue is not with the antiexploit detection, but I believe it is an issue with how I am connecting to the player.

You can check if a player spawns/respawns with CharacterAdded.

Alright. I made some changes and I will see if it works.

Oof. Didn’t work. This is the script now:

local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
     Player = player
  local Connection
  local Humanoid
  local Character = player.Character or player.CharacterAdded:Wait()
while true do
	wait(.5)

  Player.CharacterAdded:Connect(function(character)
    Character = character
    Humanoid = character:WaitForChild("Humanoid")
    
    Connection = Humanoid.StateChanged:Connect(checkstate)
  end)
end
  me = Character:WaitForChild("Humanoid")
  
end)
		

TestCounter = 0
lastTime = 0

DataStoreService = game:GetService("DataStoreService")
BanStore = DataStoreService:GetDataStore("6Hbg$%HN")
local userinfo = BanStore:GetAsync(Player.UserId)
	if userinfo == "nil" then
		return
	elseif userinfo then
		Player:kick("\n Fruitose Anti-Exploit \n  \n You have been banned for using "..userinfo.." exploits. \n  \n You may appeal this ban in our discord server. \n  \n If you believe that this is a mistake, please contact a developer.")
	end

function checkstate(state)
	
	
	if state == Enum.HumanoidStateType.Seated then
		if lastTime > os.time() - 1 then
			TestCounter = TestCounter + 1
			
			if TestCounter > 2 then

				wait(1)
		    
		Player:Kick("You have been caught using infinite jump!")
				BanStore:SetAsync(Player.UserId, "infinite jump")
			end
		else
			lastTime = os.time()
			TestCounter = 0
		end
	end
	
	
	if state == Enum.HumanoidStateType.Flying then
		
		wait(1)
	
		Player:Kick("\n Fruitose Anti Exploit \n You have been kicked \n Reason: Added body velocity (Flying)")
		BanStore:SetAsync(Player.UserId, "fly")
	end
	
	if state == Enum.HumanoidStateType.StrafingNoPhysics then
		
		wait(1)
	
		Player:Kick("\n Fruitose Anti Exploit \n You have been banned. \n Reason: Disallowed state change (Noclip)\n You may appeal this ban in our discord server")
		BanStore:SetAsync(Player.UserId, "noclip")
	end
	
	if me.WalkSpeed > 18 then
		
		wait(1)
	
		Player:Kick("\n Fruitose Anti Exploit \n You have been kicked \n Reason: Walkspeed change detetcted (Speed Exploits)")
			BanStore:SetAsync(Player.UserId, "walkspeed")	
		
	end
	if me.JumpPower > 50 then
		
		wait(1)
	
		Player:Kick("\n Fruitose Anti Exploit \n You have been kicked \n Reason: Jumppower change detetcted (Jump exploits)")
			BanStore:SetAsync(Player.UserId, "jumppower")	
	end
	
end

me.StateChanged:Connect(checkstate)

Do not kick or ban the player for exploiting, false positives can and will happen on any anti-exploit in the server involving the character. You should instead have a less severe punishment, such as respawning the player, or teleporting them back to the last known valid position. You should also only use the Position property, preferably on the HunanoidRootPart, as pretty much any other property can be spoofed. To patch TP/speed exploits, just check their last position with the current position with

local distance = Vector3.new(LastCFrame.X, 0, LastCFrame.Z) - Vector3.new(CurrentCFrame.X, 0, CurrentCFrame.Z).Magnitude
if distance > (Humanoid.Walkspeed + 10) then -- we check Humanoid.Walkspeed on the server in case you have a real reason to speed the player
	-- do you anti exploits here
end

-- you can also check if their distance if very far away, and they are obviously exploiting, respawn them
if distance > (Humanoid.Walkspeed * 10) then
	-- respawn the player
elseif distance > (Humanoid.Walkspeed + 10) then
	-- just TP them back
end

This is just an example, and in your code, you should modify it so that it looks for multiple trips instead of one (unless they moved very far and it is obvious that they are exploiting)

You can stop fly/gravity exploits by checking 2 things, you can use raycasts to see when they are on the ground, and if there position is too high from when they were last on the ground, and if they were too high from the ground when they were last on the ground. You can also check if they are hovering in the air without a negative Y velocity for too long. You can also use raycasts to check if a player no clipped through a wall. One last thing, do not use a Script in the StarterCharacterScripts, cause any Instance in the players character that is not a BasePart can be destroyed and will replicate, this is an undocumented replication behaviour that can actually allow exploiters to destroy your anti-exploit scripts. Instead, do this

local function OnCharacterAdded(char)
	-- anti-exploits
end

local function OnPlayerAdded(plr)
	plr.CharacterAppearanceLoaded:Connect(OnCharacterAdded)
	if plr:HasAppearanceLoaded() then -- if the character appearance already loaded
		OnCharacterAdded(plr.Character)
	end
end

Players.PlayerAdded:Connect(OnPlayerAdded)
-- loop through GetPlayers in case the player was added before the connection was made
for i, plr in ipairs(Players:GetPlayers()) do
	OnPlayerAdded(plr)
end
1 Like

Thanks for the help, but this isn’t the issue. All of the antiexploit detection such as walkspeed, noclip, etc work perfectly and I have not changed them at all. The issue is with the CharacterAdded function which I have been unable to find the cause of the issue of it. While I do realize that false bans may happen, this is for a cafe/ working group where we are targeted by exploiters frequently and have an appeals system. Regarding the StarterCharacterScripts, this script is in ServerScriptService so that players are not able to delete it.

You still have to be careful, you would have to check a lot of people saying they got falsely banned and finding out which ones are actually false, and, you should use the ways of checking using the Position property only cause any other property can be spoofed. Exploiters also won’t want to exploit if their exploit just don’t work, a lot of this info came out of this thread actually, so you can take a look at it if you want

  Player.CharacterAdded:Connect(function(character)
    Character = character
    Humanoid = character:WaitForChild("Humanoid")
    Connection = Humanoid.StateChanged:Connect(checkstate)

Im confused, why do you need a loop?? Also if you still want to use a loop then wrap them inside a pcall to avoid the loop breaking.

If this is on the server, then no, it does not work. WalkSpeed and JumpPower are being checked on the server, and those are not replicated. These checks will not work.

Hm that’s weird. It was working on the server for me. I will ask a friend of mine what I’m doing wrong tomorrow. Thanks anyways.

The antiexploit was working before, except that if the player reset, it would stop detecting them. Someone in the roblox discord suggested that I change it to the main connection code shown there. I know for a fact that the stuff in the checkstate function works because it was working earlier today and I have not changed anything.

Studio isn’t the most accurate on replication, because when I delete scripts in studio, only the first one replicates (unless I use a LocalScript to delete them), so that might be the problem.

I’ve been publishing and testing from the normal client