Hi. Today and yesterday, I asked ChatGPT to write me a script that kicks exploiters for using firetouchinterest function in an executor. I have a friend to test it, so we began testing that anti cheat. He executed firetouchinterest in my game when he was 8 studs away the part which had this script inside and got kicked. The script has a function that disables that anti cheat for some amount of time (or permanently) if you’ll run _G.DisableAntiCheatDetection(game.Players.MyUsername, 100) - it disables ALL in-game anti cheat detections for 100 seconds.
So, the problem is that when I give my friend invincibility from anti cheat detections for 5 seconds, he fires firetouchinterest function instantly (when the timer still runs). It works like it should to - he doesn’t get kicked. Then, when the timer expires, he uses it again - and he doesn’t get any kick. The issue is that when the player uses firetouchinterest, it NEVER makes the game think that you left that part, so it won’t detect firetouchinterest until you’ll MANUALLY jump on the part and leave it. Because of leaving the part manually, it will make the game think that you left the part, because you actually left it.
Because of that issue, I’m asking y’all here. Can you fix the script and make it detect firetouchinterest even after the timer ends? I asked ChatGPT for 4 hours straight and he didn’t help me.
Here’s the script which I put in the part:
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Part = script.Parent
local MaxTouchDistance = 8
local TouchDebounce = 0.3
local LastTouchTimes = {}
local IsTouchingPart = {}
local AbuseDuringExempt = {}
local function IsExempt(Player)
local State = _G.PlayerStates and _G.PlayerStates[Player]
return State and type(State.ExemptUntil) == "number" and tick() <= State.ExemptUntil
end
Players.PlayerAdded:Connect(function(Player)
LastTouchTimes[Player] = 0
IsTouchingPart[Player] = false
AbuseDuringExempt[Player] = false
Player.CharacterAdded:Connect(function(Character)
LastTouchTimes[Player] = 0
IsTouchingPart[Player] = false
AbuseDuringExempt[Player] = false
local Humanoid = Character:WaitForChild("Humanoid")
Humanoid.Died:Connect(function()
LastTouchTimes[Player] = 0
IsTouchingPart[Player] = false
AbuseDuringExempt[Player] = false
end)
end)
end)
Players.PlayerRemoving:Connect(function(Player)
LastTouchTimes[Player] = nil
IsTouchingPart[Player] = nil
AbuseDuringExempt[Player] = nil
end)
Part.Touched:Connect(function(Hit)
local Player = Players:GetPlayerFromCharacter(Hit.Parent)
if not Player then return end
local Character = Player.Character
if not Character then return end
local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
if not HumanoidRootPart then return end
local CurrentTime = tick()
if CurrentTime - (LastTouchTimes[Player] or 0) < TouchDebounce then return end
LastTouchTimes[Player] = CurrentTime
local Distance = (Part.Position - HumanoidRootPart.Position).Magnitude
local Exempt = IsExempt(Player)
if Distance <= MaxTouchDistance + Part.Size.Magnitude / 2 then
-- Player physically touched the part
IsTouchingPart[Player] = true
-- Reset abuse flag if not exempt
if not Exempt then
AbuseDuringExempt[Player] = false
end
return
end
if Distance > MaxTouchDistance then
if Exempt then
-- Exploit during exemption: mark abuse and force leaving
AbuseDuringExempt[Player] = true
IsTouchingPart[Player] = false -- Force "left"
else
-- Kick immediately on abuse outside exemption
if AbuseDuringExempt[Player] then
Player:Kick("Exploits detected: Firetouchinterest (post-exemption).")
return
end
Player:Kick("Exploits detected: Firetouchinterest.")
end
end
end)
RunService.Heartbeat:Connect(function()
for _, Player in ipairs(Players:GetPlayers()) do
local Character = Player.Character
if not Character then continue end
local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
if not HumanoidRootPart then continue end
local Distance = (Part.Position - HumanoidRootPart.Position).Magnitude
local CloseEnough = Distance <= MaxTouchDistance + Part.Size.Magnitude / 2
local Exempt = IsExempt(Player)
-- Manual check: if script thinks player is touching but distance is now too far, mark left immediately
if IsTouchingPart[Player] and not CloseEnough then
IsTouchingPart[Player] = false
-- Kick if abuse happened during exemption and exemption expired
if not Exempt and AbuseDuringExempt[Player] then
Player:Kick("Exploits detected: Firetouchinterest (left part after exemption).")
AbuseDuringExempt[Player] = false
end
end
end
end)
It works fine, but if you give yourself invincibility, INSTANTLY use firetouchinterest and then the timer expires - it won’t work, because it never registered that it left the part (until you touch and leave that part manually).
Here’s the script from ServerScriptService, where the _G.DisableAntiCheatDetection function comes from:
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local MaxAllowedAirTime = 2
local MaxAllowedTeleportDistance = 10
local TeleportIntervalInSeconds = 0.1
local GracePeriod = 5
local FallingSpeedThreshold = -50
local PostLadderForgivenessTime = 3
local LadderCloseRange = 8
local GraceJumpTime = 1
local JumpCooldown = 0.2
local JumpValidationDelay = 0.1
local MinUngroundedTimeForKick = 0.2
local PlayerStates = {}
_G.PlayerStates = PlayerStates
local function IsTouchingTruss(HumanoidRootPart)
if not HumanoidRootPart then return false end
for _, Part in ipairs(HumanoidRootPart:GetTouchingParts()) do
if Part:IsA("TrussPart") then return true end
end
return false
end
local function IsNearTruss(HumanoidRootPart)
if not HumanoidRootPart then return false end
for _, Part in ipairs(workspace:GetPartBoundsInRadius(HumanoidRootPart.Position, LadderCloseRange)) do
if Part:IsA("TrussPart") then return true end
end
return false
end
local function IsGrounded(Humanoid)
return Humanoid and Humanoid.FloorMaterial ~= Enum.Material.Air
end
local function IsFallingFast(HumanoidRootPart)
return HumanoidRootPart and HumanoidRootPart.Velocity.Y < FallingSpeedThreshold
end
local function IsClimbing(Humanoid)
return Humanoid and Humanoid:GetState() == Enum.HumanoidStateType.Climbing
end
local function InitPlayer(Player)
PlayerStates[Player] = {
LastPosition = nil,
LastCheckingTime = 0,
FlyingTime = 0,
SpawnTime = tick(),
LastLeftLadderTime = nil,
LastJumpTime = 0,
LastGrounded = true,
ExemptUntil = 0,
UngroundedStartTime = nil
}
end
local function RemovePlayer(Player)
PlayerStates[Player] = nil
end
_G.DisableAntiCheatDetection = function(Player, Duration)
local State = PlayerStates[Player]
if State then
State.ExemptUntil = tick() + (Duration or math.huge)
end
end
Players.PlayerAdded:Connect(function(Player)
InitPlayer(Player)
Player.CharacterAdded:Connect(function(Character)
local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
InitPlayer(Player)
local State = PlayerStates[Player]
State.SpawnTime = tick()
State.LastJumpTime = 0
State.LastGrounded = true
State.UngroundedStartTime = nil
Humanoid.StateChanged:Connect(function(_, NewState)
local Now = tick()
if NewState == Enum.HumanoidStateType.Jumping then
if Now - State.SpawnTime < GraceJumpTime then return end
if Now - State.LastJumpTime < JumpCooldown then return end
State.LastJumpTime = Now
task.delay(JumpValidationDelay, function()
if not Player.Character then return end
local CurrentHumanoid = Player.Character:FindFirstChildOfClass("Humanoid")
local HRP = Player.Character:FindFirstChild("HumanoidRootPart")
if not CurrentHumanoid or not HRP then return end
local Grounded = IsGrounded(CurrentHumanoid)
local TouchingLadder = IsTouchingTruss(HRP)
local NearLadder = IsNearTruss(HRP)
local Climbing = IsClimbing(CurrentHumanoid)
local FullyGrounded = Grounded or TouchingLadder or NearLadder or Climbing
local StateNow = PlayerStates[Player]
if not StateNow then return end
if tick() <= StateNow.ExemptUntil then return end
local UngroundedTime = StateNow.UngroundedStartTime and (tick() - StateNow.UngroundedStartTime) or 0
if not FullyGrounded and UngroundedTime >= MinUngroundedTimeForKick then
Player:Kick("Exploits detected: Infinite jump.")
end
end)
end
end)
end)
end)
Players.PlayerRemoving:Connect(RemovePlayer)
RunService.Heartbeat:Connect(function(Dt)
local Now = tick()
for _, Player in ipairs(Players:GetPlayers()) do
local State = PlayerStates[Player]
if not State then continue end
local Character = Player.Character
if not Character then continue end
local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
if not HumanoidRootPart or not Humanoid then continue end
local Position = HumanoidRootPart.Position
local Grounded = IsGrounded(Humanoid)
local TouchingLadder = IsTouchingTruss(HumanoidRootPart)
local NearLadder = IsNearTruss(HumanoidRootPart)
local Climbing = IsClimbing(Humanoid)
local FallingFast = IsFallingFast(HumanoidRootPart)
local Exempt = Now <= (State.ExemptUntil or 0)
if Exempt then
State.LastPosition = Position
State.LastCheckingTime = Now
State.FlyingTime = 0
State.LastLeftLadderTime = nil
State.LastGrounded = true
State.UngroundedStartTime = nil
continue
end
local FullyGrounded = Grounded or TouchingLadder or NearLadder or Climbing
if FullyGrounded then
State.UngroundedStartTime = nil
else
if not State.UngroundedStartTime then
State.UngroundedStartTime = Now
end
end
State.LastGrounded = FullyGrounded
if Now - State.SpawnTime < GracePeriod then
State.LastPosition = Position
State.LastCheckingTime = Now
State.FlyingTime = 0
continue
end
local RecentlyLeftLadder = State.LastLeftLadderTime and (Now - State.LastLeftLadderTime <= PostLadderForgivenessTime)
if not TouchingLadder and not NearLadder then
if not State.LastLeftLadderTime then
State.LastLeftLadderTime = Now
end
else
State.LastLeftLadderTime = nil
end
if TouchingLadder or NearLadder or Climbing then
State.FlyingTime = 0
else
if not Grounded and not FallingFast then
State.FlyingTime += Dt
if State.FlyingTime >= MaxAllowedAirTime then
Player:Kick("Exploits detected: Flying.")
continue
end
else
State.FlyingTime = 0
end
end
if State.LastPosition and Now - State.LastCheckingTime >= TeleportIntervalInSeconds then
local Delta = Position - State.LastPosition
local Horizontal = Vector3.new(Delta.X, 0, Delta.Z).Magnitude
local Vertical = math.abs(Delta.Y)
local ClosestLadder = math.huge
for _, Part in ipairs(workspace:GetDescendants()) do
if Part:IsA("TrussPart") then
local Dist = (Position - Part.Position).Magnitude
if Dist < ClosestLadder then ClosestLadder = Dist end
end
end
local LadderForgiveness = RecentlyLeftLadder and ClosestLadder <= LadderCloseRange and Horizontal <= MaxAllowedTeleportDistance * 2 and Vertical <= MaxAllowedTeleportDistance * 2
if Horizontal > MaxAllowedTeleportDistance and not FallingFast and not LadderForgiveness then
Player:Kick("Exploits detected: Teleporting.")
continue
end
State.LastPosition = Position
State.LastCheckingTime = Now
elseif not State.LastPosition then
State.LastPosition = Position
State.LastCheckingTime = Now
end
end
end)
Can anyone fix that issue? Firetouchinterest never makes the game’s logic think that you left the part, so if you used firetouchinterest while you’re invincible from anti cheat detections and then the timer expires, it won’t kick you because it thinks that you’re still standing on the part.