Détecter des bots dans un MMORPG : l'accumulation de poids côté serveur
Les bots ne se détectent pas avec une règle binaire. Voici comment j'ai construit un service de détection par accumulation de poids sur Dofus Touch, et pourquoi cette approche évite les faux positifs.
Sur Dofus Touch, j’ai construit un service de détection de bots côté serveur. La tentation, quand on attaque ce problème, c’est de coder des règles dures : “si le joueur clique exactement toutes les 800 ms pendant deux heures, c’est un bot”. Ça marche cinq minutes, jusqu’à ce que le bot ajoute un peu de jitter et redevienne invisible. Et pendant ces cinq minutes, vous bannissez aussi des vrais joueurs qui ont juste un pattern régulier.
L’approche qui tient, c’est l’accumulation de poids. Voici l’idée.
Principe
Chaque action joueur contribue à un ou plusieurs compteurs pondérés. Aucun signal pris isolément ne déclenche un ban. Mais quand plusieurs signaux convergent dans la durée, le score global franchit un seuil, et le compte est flaggé.
C’est l’équivalent low-tech d’une feature engineering pour un modèle de scoring : on encode du domain knowledge dans des poids, on observe la distribution, on ajuste.
Quels signaux
Sur un MMORPG, les signaux utiles ne sont jamais “une seule métrique”. C’est un faisceau :
- Régularité temporelle des clics (variance trop basse = suspect)
- Patterns de mouvement (chemins toujours identiques au pixel près)
- Séquences d’inventaire (drag and drop avec un timing parfait)
- Cycles de combat répétés (même séquence de sorts, même cible, en boucle)
- Connexion 24/7 sans déconnexion humaine (les vrais joueurs vont aux toilettes)
- Trajets de farming optimaux (un humain prend toujours un détour)
Chaque signal a un poids. Certains sont rouges (timing parfait au millième de seconde sur 1000 actions), d’autres sont jaunes (jamais de pause de plus de 30 minutes sur 12 heures).
Architecture
Côté serveur, l’implémentation est volontairement simple :
// Pseudo-code Java
public class BotScoreAccumulator {
private final Map<PlayerId, ScoreState> scores;
public void onEvent(PlayerEvent event) {
ScoreState state = scores.computeIfAbsent(event.playerId(), ScoreState::new);
for (Detector detector : detectors) {
double weight = detector.evaluate(event, state.history());
state.add(detector.id(), weight);
}
if (state.totalScore() > FLAG_THRESHOLD) {
flagForReview(event.playerId(), state.snapshot());
}
}
}
Quelques choix structurants :
- Le scoring est en mémoire, persisté périodiquement. On veut pouvoir évaluer en temps réel sans round-trip DB par event.
- Décrément temporel : les poids s’érodent dans le temps. Un comportement suspect d’il y a trois jours pèse moins qu’il y a trois minutes. Sinon, on accumule à l’infini et tout le monde finit suspect.
- Snapshot lors du flag : quand le seuil est atteint, on sauvegarde l’état complet (quels détecteurs ont contribué, à quels poids, sur quelle fenêtre temporelle) pour pouvoir auditer la décision a posteriori.
Pourquoi pas du vrai ML
J’ai considéré une approche ML pure (random forest sur features extraites, ou modèle sequence). Pour ce contexte précis, j’ai choisi de ne pas le faire. Voici pourquoi.
- Auditabilité : quand un joueur conteste un ban, je peux montrer “voici les détecteurs qui ont déclenché, avec leurs poids exacts”. Avec un classifieur boîte noire, c’est beaucoup plus dur.
- Évolution rapide : ajouter un nouveau signal, c’est ajouter un détecteur de quelques lignes de code. Avec un modèle ML, il faut re-entraîner, valider, redéployer.
- Coût : zéro infra GPU, zéro MLOps. Un service Java standard.
- Jeu chat-souris : les bots évoluent. Les détecteurs heuristiques s’ajustent en quelques jours, un modèle ML demande un cycle complet.
ML aurait été le bon choix si j’avais voulu classifier des comportements complexes en zero-shot sur de nouveaux types de bots. Pour la détection de bots de farming sur un MMORPG bien connu, l’heuristique pondérée est plus rapide à itérer et plus défendable opérationnellement.
Faux positifs : le vrai juge de paix
Le vrai test d’un système anti-bot, ce n’est pas “combien de bots a-t-il bannis”. C’est “combien de vrais joueurs a-t-il bannis par erreur”. Un seul ban abusif sur un joueur populaire et c’est la community manager qui crame son weekend.
Deux garde-fous :
- Étape “review” entre flag et ban. Le seuil de flag déclenche une enquête (par un GM ou par un service tiers), pas un ban automatique. Le seuil de ban automatique est nettement plus élevé.
- Boucle de feedback : chaque ban manuel ou levée de ban remonte dans l’analyse pour ajuster les poids.
Ce que j’en retiens
- Les heuristiques pondérées valent mieux que des règles binaires sur ce genre de problème.
- L’accumulation temporelle avec décroissance évite la dérive.
- L’auditabilité est un feature, pas un nice-to-have. Quand un joueur conteste, vous devez pouvoir expliquer.
- Le ML viendrait après, sur les cas que les heuristiques n’attrapent pas.
Sur Dofus Touch, ce système a réduit le nombre de comptes non humains. Pas avec une grande révolution algorithmique : juste une bonne discipline de modélisation du domaine et une rigueur sur les faux positifs.