--!strict --[[ AntiCheat.luau (SERVER) MVP-level movement sanity check. Not a fortress — a speed bump that catches obvious speed/teleport hacks. Because money & car ownership are ALREADY server-authoritative (Economy validates everything), the main client attack surface left is movement, so we watch that. Approach: sample each player's HRP position periodically; if they cover ground implying a sustained speed above MaxPlausibleSpeed, snap them back to their last valid position. Generous threshold to avoid false positives from legit fast cars. ]] local Players = game:GetService("Players") local RunService = game:GetService("RunService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local GameConfig = require(ReplicatedStorage.Shared.GameConfig) local AntiCheat = {} type Track = { lastPos: Vector3, lastValid: CFrame } local tracked: { [Player]: Track } = {} local SAMPLE_INTERVAL = 0.5 -- Server-initiated teleports (car spawn onto the pad, respawn, mode resets) -- legitimately move a player thousands of studs in one frame, which trips the -- speed check and snaps them straight back -- dragging their car with them. -- Callers announce those moves via AntiCheat.grant() so the next sample is -- accepted as the new baseline instead of treated as a hack. local graceUntil: { [Player]: number } = {} local GRACE_SECONDS = 2 --- Exempt a player from the speed check briefly after a legitimate teleport. function AntiCheat.grant(player: Player, seconds: number?) graceUntil[player] = os.clock() + (seconds or GRACE_SECONDS) end local function hrpOf(player: Player): BasePart? local char = player.Character return char and char:FindFirstChild("HumanoidRootPart") :: BasePart? end function AntiCheat.init() local function watch(player: Player) player.CharacterAdded:Connect(function(char) local hrp = char:WaitForChild("HumanoidRootPart", 10) :: BasePart? if hrp then tracked[player] = { lastPos = hrp.Position, lastValid = hrp.CFrame } end end) end for _, p in ipairs(Players:GetPlayers()) do watch(p) end Players.PlayerAdded:Connect(watch) Players.PlayerRemoving:Connect(function(p) tracked[p] = nil end) local accum = 0 RunService.Heartbeat:Connect(function(dt) accum += dt if accum < SAMPLE_INTERVAL then return end local interval = accum accum = 0 for player, track in pairs(tracked) do local hrp = hrpOf(player) if not hrp then continue end local pos = hrp.Position -- Falling doesn't count (avoid flagging big drops). Only guard XZ plane. local horizontal = Vector3.new(pos.X - track.lastPos.X, 0, pos.Z - track.lastPos.Z).Magnitude local hSpeed = horizontal / interval local inGrace = (graceUntil[player] or 0) > os.clock() if hSpeed > GameConfig.MaxPlausibleSpeed and not inGrace then -- Snap back: likely a speed/teleport hack. hrp.CFrame = track.lastValid hrp.AssemblyLinearVelocity = Vector3.zero else track.lastValid = hrp.CFrame end track.lastPos = hrp.Position end end) end return AntiCheat