Dans les jeux multijoueurs Roblox, les scripts anti-triche côté client sont inefficaces face aux injecteurs de mémoire modernes capables d'intercepter et de modifier les LocalScripts.
Pour garantir l'équité des parties, une approche autoritaire sur le serveur est indispensable. En mesurant les déplacements par delta-temps, en vérifiant les murs via raycasts et en appliquant un retour en arrière fluide, le jeu reste parfaitement sécurisé.
1. Pourquoi les anti-cheats locaux échouent
Comprendre l'environnement d'exécution des exploits sur le client Roblox :
- Compromission locale : Le hookmetamethod permet aux attaquants d'altérer les arguments réseau.
- Destruction de scripts : Tout script client peut être mis en pause ou supprimé.
- Propriété physique : Le client possède l'autorité physique directe sur son HumanoidRootPart.
- Principe Zéro Confiance : Toute coordonnée reçue du client doit être vérifiée par le serveur.
2. Vérification serveur de la vitesse et de la téléportation
Mesure des déplacements sans fausses alertes dues aux variations de ping :
- Calcul de déplacement : Distance euclidienne entre la position actuelle et précédente.
- Seuil dynamique : Marge autorisée basée sur la WalkSpeed et la latence réseau.
- Fenêtre d'anomalies : Accumulation d'écarts suspects avant toute sanction.
- Rubberbanding : Réinitialisation immédiate vers la dernière position validée.
--!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. Prévention du noclip par raycast spatial
Empêcher le franchissement illégal des murs et limites de zone :
- Raycast de trajectoire : Détection d'intersection avec des pièces solides CanCollide.
- Capsule multi-rayons : Contrôles aux niveaux des pieds, du torse et de la tête.
- Filtrage dynamique : Exclusion des éléments décoratifs sans collision physique.
- Téléportations légitimes : Déclaration serveur préalable avant déplacement.
4. Compensation de latence et tolérance au jitter
Trouver l'équilibre entre sécurité et jouabilité pour connexions instables :
- Mesure du ping : Adaptation automatique des marges de déplacement.
- Absorption des rafales : Gestion des paquets retardés sur connexions mobiles.
- Historique serveur : Tampon circulaire pour la validation rétroactive des tirs.
- Alertes visuelles : Avertissements réseau plutôt que déconnexions brutales.
5. Architecture de production et performance
Déploiement sur serveurs à forte charge sans perte de performance :
- Validation par lots : Échelonnement des joueurs sur images paires et impaires.
- Télémétrie silencieuse : Envoi d'alertes discrètes vers des webhooks externes.
- Instantanés de relecture : Conservation en mémoire des trajectoires anormales.
- Paramètres moteur : Activation de RejectCharacterDeletions et CollisionGroups stricts.
Frequently Asked Questions
Pourquoi ne pas vérifier la vitesse dans un LocalScript ?
Le client a le contrôle total de sa mémoire locale et peut contourner ou désactiver ces scripts.
Comment gérer les projections ou propulsions légitimes ?
Le serveur enregistre l'impulsion et élargit temporairement le seuil de déplacement autorisé.
Le raycasting sur serveur ralentit-il le jeu ?
Pour 50 joueurs, 50 raycasts optimisés consomment moins de 0.2 ms de CPU par image.