Em jogos multijogador no Roblox, scripts anti-cheat no cliente são inúteis contra injetores de memória modernos capazes de desativar ou manipular LocalScripts.
Para garantir partidas justas, é essencial um modelo autoritativo no servidor. Ao rastrear deslocamentos em delta-time, verificar colisões com raycasts e aplicar rubberbanding, o jogo permanece imune a trapaças.
1. Por que anti-cheats no cliente falham
Compreendendo como funcionam as explorações no cliente do Roblox:
- Comprometimento local: Funções como hookmetamethod permitem interceptar chamadas remotas.
- Destruição de scripts: Scripts no cliente podem ser pausados ou deletados livremente.
- Autoridade física da rede: O cliente controla a física de seu próprio HumanoidRootPart.
- Princípio de Confiança Zero: Nunca confie em informações de posição enviadas pelo cliente.
2. Verificação de velocidade e teletransporte no servidor
Medição de deslocamento por frame sem falsos positivos causados por lag:
- Cálculo de delta-time: Medição da distância euclidiana entre coordenadas consecutivas.
- Teto dinâmico de velocidade: Limite baseado em WalkSpeed somado à tolerância de ping.
- Buffer de anomalias: Acúmulo de discrepâncias antes de acionar punições.
- Rubberbanding: Reposicionamento imediato para a última coordenada válida.
--!strict
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local AntiCheatService = {}
type PlayerRecord = {
lastPosition: Vector3,
lastTick: number,
anomalyBuffer: number,
isFalling: boolean
}
local trackedPlayers: { [Player]: PlayerRecord } = {}
local RAY_PARAMS = RaycastParams.new()
RAY_PARAMS.FilterType = RaycastFilterType.Exclude
function AntiCheatService.InitPlayer(player: Player)
local char = player.Character or player.CharacterAdded:Wait()
local hrp = char:WaitForChild("HumanoidRootPart") :: BasePart
trackedPlayers[player] = {
lastPosition = hrp.Position,
lastTick = os.clock(),
anomalyBuffer = 0,
isFalling = false
}
end
function AntiCheatService.OnHeartbeat(dt: number)
local now = os.clock()
for player, record in pairs(trackedPlayers) do
local char = player.Character
if not char then continue end
local hrp = char:FindFirstChild("HumanoidRootPart") :: BasePart?
local humanoid = char:FindFirstChildOfClass("Humanoid")
if not hrp or not humanoid or humanoid.Health <= 0 then continue end
local currentPos = hrp.Position
local displacement = (currentPos - record.lastPosition).Magnitude
local maxAllowed = (humanoid.WalkSpeed * dt * 1.35) + 0.5
if displacement > maxAllowed and not record.isFalling then
record.anomalyBuffer += (displacement - maxAllowed)
if record.anomalyBuffer > 15 then
hrp.CFrame = CFrame.new(record.lastPosition)
hrp.AssemblyLinearVelocity = Vector3.zero
record.anomalyBuffer = 0
continue
end
else
record.anomalyBuffer = math.max(0, record.anomalyBuffer - (dt * 5))
end
RAY_PARAMS.FilterDescendantsInstances = { char }
local dir = currentPos - record.lastPosition
if dir.Magnitude > 0.1 then
local hit = Workspace:Raycast(record.lastPosition, dir, RAY_PARAMS)
if hit and hit.Instance and hit.Instance.CanCollide then
hrp.CFrame = CFrame.new(record.lastPosition)
hrp.AssemblyLinearVelocity = Vector3.zero
continue
end
end
record.lastPosition = currentPos
record.lastTick = now
end
end
RunService.Heartbeat:Connect(AntiCheatService.OnHeartbeat)
Players.PlayerAdded:Connect(AntiCheatService.InitPlayer)
return AntiCheatService
3. Prevenção de noclip e invasão de paredes com raycasting
Bloqueando jogadores que atravessam paredes sólidas e cofres:
- Raycast de trajetória: Verificação de interseção entre a posição anterior e a atual.
- Cápsula de múltiplos raios: Três raios paralelos (pés, tronco e cabeça).
- Filtro dinâmico: Exclusão de itens visuais sem colisão ativada.
- Teleportes legítimos: Atualização prévia de coordenadas via rotinas do servidor.
4. Compensação de latência e absorção de oscilações de ping
Segurança balanceada para jogadores com conexão instável:
- Monitoramento de RTT: Ajuste automático de tolerâncias conforme o ping oscila.
- Absorção de rajadas: Gestão de pacotes acumulados em redes móveis.
- Rollback no servidor: Buffer de coordenadas históricas para validação de disparos.
- Alertas de rede: Avisos visuais na tela antes de tomar medidas punitivas.
5. Arquitetura de produção e telemetria
Execução de verificações contínuas sem comprometer a taxa de quadros do servidor:
- Divisão em lotes: Verificação alternada de jogadores em quadros pares e ímpares.
- Registro silencioso: Envio de logs para webhooks externos sem alertar o trapaceiro.
- Histórico para auditoria: Armazenamento dos últimos segundos de movimento suspeito.
- Regras do motor: Ativação de RejectCharacterDeletions e CollisionGroups bem definidos.
Frequently Asked Questions
Por que checar velocidade no LocalScript não funciona?
O cliente tem controle sobre sua própria memória e pode burlar ou desativar o script facilmente.
Como evitar falsos positivos com knockback ou explosões?
O servidor registra a habilidade e expande temporariamente a tolerância de deslocamento do jogador.
Fazer raycasts no servidor gera lag?
Para 50 jogadores, 50 raycasts consomem menos de 0.2 ms de CPU por quadro quando otimizados.