Anti-exploit. Is it good or bad?

Hello devs.
Today I was working on my game and i started making anti exploit.
I’ve just done it and i want too see if its going to work.

The anti exploit includes:
1 script
1 module script

Here is the code

Script :

local PartChecker = require(script.PartChecker)

game.Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Char)
		local HRP = Char:WaitForChild("HumanoidRootPart")
		local Hum = Char.Humanoid

		local function WalkJumpAntiExploit()
			if Player.Character then
				if Hum then
					Hum.WalkSpeed -= 0.1 
					Hum.WalkSpeed += 0.1
					Hum.JumpPower -= 0.1
					Hum.JumpPower += 0.1
				end
			end
		end

		Hum.Running:Connect(function(speed)
			WalkJumpAntiExploit()
		end)

		Hum:GetPropertyChangedSignal("Jump"):Connect(function()
			WalkJumpAntiExploit()
		end)

		game:GetService("RunService").Heartbeat:Connect(function()
			WalkJumpAntiExploit()			
		end)

		HRP.Touched:Connect(function(hit)
			if not hit:IsDescendantOf(Char) then
				if hit.CanCollide == true then
					local success,err = pcall(function()
						local IsInside,percentage = PartChecker.IsPartInsidePart(HRP,hit)

						if IsInside == true then
							Player:LoadCharacter()
						end
					end)                        
				end
			end

			task.wait(0.2)
			if not hit:IsDescendantOf(Char) then
				if hit.CanCollide == true then
					local success,err = pcall(function()
						local IsInside,percentage = PartChecker.IsPartInsidePart(HRP,hit)

						if IsInside == true then
							Player:LoadCharacter()
						end
					end)                        
				end
			end
		end)

		Hum:GetPropertyChangedSignal("MoveDirection"):Connect(function()
			if game.Players:FindFirstChild(Player.Name) ~= nil then
				if Hum:GetState() == Enum.HumanoidStateType.PlatformStanding then
					local ray = workspace:Raycast(HRP.Position,HRP.CFrame.UpVector * -5)
					if Hum.FloorMaterial == Enum.Material.Air and ray == nil and HRP.Velocity.magnitude == 0 then
						Player:LoadCharacter()
					end
				end

				if HRP then
					if Hum:GetState() == Enum.HumanoidStateType.Swimming then
						local min = HRP.Position - (HRP.Size / 2)
						local max = HRP.Position + (1 * HRP.Size)    
						local region = Region3.new(min,max):ExpandToGrid(4)
						local material = workspace.Terrain:ReadVoxels(region,4)[1][1][1]
						if material ~= Enum.Material.Water and Hum:GetState() == Enum.HumanoidStateType.Swimming then
							Hum:ChangeState(Enum.HumanoidStateType.FallingDown)
							task.wait()
							if Hum:GetState() == Enum.HumanoidStateType.Swimming then
								Player:Kick("Bruh u cant even swim in this game")
							end
						end
					end
				end
			end
		end)
	end)
end)

Module script for collision detection:

local module = {}

function CreateExo(part)
	local Positions = {
		[1] = Vector3.new(part.Size.X/2,part.Size.Y/2,part.Size.Z/2),
		[2] = Vector3.new(-part.Size.X/2,part.Size.Y/2,-part.Size.Z/2),
		[3] = Vector3.new(part.Size.X/2,part.Size.Y/2,-part.Size.Z/2),
		[4] = Vector3.new(-part.Size.X/2,part.Size.Y/2,part.Size.Z/2),
		[5] = Vector3.new(part.Size.X/2,-part.Size.Y/2,part.Size.Z/2),
		[6] = Vector3.new(-part.Size.X/2,-part.Size.Y/2,-part.Size.Z/2),
		[7] = Vector3.new(part.Size.X/2,-part.Size.Y/2,-part.Size.Z/2),
		[8] = Vector3.new(-part.Size.X/2,-part.Size.Y/2,part.Size.Z/2),
	}

	if part:IsA("Part") then
		if part.Shape ~= Enum.PartType.Block then	
			Positions = {
				[1] = Vector3.new(0,part.Size.Y/2,0),
				[2] = Vector3.new(0,-part.Size.Y/2,0),
				[3] = Vector3.new(part.Size.X/2,0,0),
				[4] = Vector3.new(-part.Size.X/2,0,0),
				[5] = Vector3.new(0,0,part.Size.Z/2),
				[6] = Vector3.new(0,0,-part.Size.Z/2),
			}
		end
	end

	local atts = {}
	for i,v in pairs(Positions) do
		local att = Instance.new("Attachment",part)
		att.Position = v
		att.Name = "_[att]_"..i
		table.insert(atts,att)
	end

	return atts
end

function module.IsPartInsidePart(part1,part2)
	local Exo = CreateExo(part1)

	local Checker = Instance.new("Attachment",part2)

	local IsInPart = true
	
	local AreIn = #Exo
	for _,v in pairs(Exo) do
		Checker.WorldPosition = v.WorldPosition
		v:Destroy()
		
		if math.abs(Checker.Position.X) > part2.Size.X/2 then IsInPart = false AreIn -= 1 continue end
		if math.abs(Checker.Position.Y) > part2.Size.Y/2 then IsInPart = false AreIn -= 1 continue end        
		if math.abs(Checker.Position.Z) > part2.Size.Z/2 then IsInPart = false AreIn -= 1 continue end
	end

	return IsInPart, AreIn/#Exo * 100
end

return module

Feel free to use it if its a good one. Supports

  • Anti speed and jump power change
  • Prevents swimming exploit (really sensitive)
  • Prevents flying
2 Likes

Because exploiters have full control of the Roblox client, they can just block replication to these properties if it gets in the way.

This is too much. You can just have the .Heartbeat connection.

I’m thinking that this could cause problems, because humanoids make certain parts(arms, legs) in the character non-collidable, leading to them very easily clipping into things. .Touched might fire even if something isn’t intersecting with another thing, AFAIK.

I’ll try testing this out to see if I can find any problems.

It looks like the noclip is a bit broken, disabling .CanCollide on a part causes .Touched to not always fire, it seems (.CanCollide disabled on client, it’s collidable on the server, but the server is listening for .Touched on the player’s character’s humanoidrootpart, so the client tells the server when it touches something).

Also, it appears running

local chr = workspace:WaitForChild(game.Players.LocalPlayer.Name)

while true do
task.wait()
chr:WaitForChild("Humanoid").WalkSpeed = 100
end

In the output on the client will somewhat consistently allow you to walk faster than normal.

I suggest you use regular techniques for an anti-exploit

--Noclip

RunService.Heartbeat:Connect(function()
    local HRPRegion = --Define as a 1x1x1 Region3 at the player's HRP
    --Bit too much to write as an example without a standalone post
    if workspace:FindPartsInRegion3WithIgnoreList(HRPRegion, {Character}, 1) > 0 then
        --Teleport player to last valid position
    end
end)

--Anti-walkspeed

local LastPosition = HRP.Position

RunService.Heartbeat:Connect(function(Delta)
    if (LastPosition - HRP.Position).Magnitude > (DefaultWalkSpeed + 10) * Delta then
        HRP.CFrame = CFrame.new(LastPosition)
    else
        LastPosition = HRP.Position
    end
end)

Thanks for the suggestion, but i already did something else to detect the collision

This seems to not work properly and it constantly returns the player when he tries to walk and jump at the same time. (also this prevents any type of velocity based mechanics)

I spent 5 minutes on it, it won’t really be a top-tier god-level unbypassable anti-cheat with 0 flaws, it was just an example :sweat_smile:

Good, you shouldn’t rely on .Touched events for anti-cheats.

About that…
I’ve did some tests with the Touched.
Touched works just fine since its server sided (meaning Touching will fire no matter what happens)
Disabling CanTouch on the client results no change whatsoever.
Destroying the part will result the same behavior

The only issue with it is the delay

That’s odd, the script you provided had basically no anti-noclip for me, when I disabled CanCollide on the client.

Anyway, the client still controls the physics of it’s own character(as it has network ownership), meaning it fires the touched events of anything in it’s character (attached to the humanoid root part, including the HRP itself), so an exploiter can just prevent those from being fired.

Thanks for the suggestions! :grinning_face_with_smiling_eyes:

I just revamped my WalkSpeed detection and The collision one.

AntiExploit

here is the module
I will work a bit more on the swimming and fly detection since they are not mega accurate

Another method you can do in contrast to using .Touched events is raycasting in the player’s MoveDirection, waiting 1 frame (physics loop), and firing another raycast, which fires TOWARDS the last raycast, and comparing it to the last raycast. If both results hit a part, it means the player has noclipped inside of a part. Be sure to use this with for example the .Stepped event of the RunService service, as using something like a while loop may cause false-positives when the player is rounding a sharp corner. A pro to this solution is that you can directly set the HumanoidRootPart’s CFrame to the first position and reset all the values so the player isnt stuck in a loop.

antiexploit_noclipraycast.rbxl (35.0 KB)
Here is an example
(edit; For some reason I confused myself when we can just raycast from the player’s current position to the last frame’s position and it works just as well)

1 Like

Exploiters can also spoof the .Running event argument, use distant checks instead