Anticheat
O pipeline de violações descrito nesta página roda no servidor. Ele usa pacotes e respostas enviados pelo cliente, mas os confronta com o estado e os limites mantidos pelo servidor — por exemplo, um sync fora do envelope aceito, um tiro com arma que nunca foi concedida ou um pacote que chegou sem criptografia.
Ele vem ligado por padrão. set ac_enabled 0 desliga por completo.
Como funciona
Seção intitulada “Como funciona”Toda violação passa pelos mesmos quatro passos:
- Relato. Quem detectou (a thread de rede, o envelope de sync, a checagem de combate) relata a violação para um jogador. Relatos de uma família isenta são descartados aqui.
- Contagem. Cada par
(jogador, violação)mantém um contador dentro de uma janela deslizante. Quando a janela expira, o contador reinicia. - Decisão. Quando o contador atinge o limite da política, a ação dela dispara. O evento
onPlayerAnticheatViolationé emitido para cada ocorrência contada. - Punição.
kickdesconecta o jogador — a menos que um script tenha cancelado o evento dessa ocorrência, ou o modo sombra esteja ligado.
Depois que um kick dispara, a janela reinicia, para que uma punição já em andamento não dispare de novo no próximo relato da fila.
| Ação | Conta | Grava na trilha | Aparece no console | Desconecta |
|---|---|---|---|---|
ignore | não | não | não | não |
log | sim | sim | não | não |
warn | sim | sim | sim | não |
kick | sim | sim | sim | sim |
As únicas ações aceitas são ignore, log, warn e kick. Banimentos persistentes devem ser implementados pelo próprio resource.
O evento Lua roda depois da contagem, da escrita na trilha e da mensagem de console. Portanto, cancelEvent() impede apenas o kick daquela ocorrência; ele não apaga o registro nem desfaz a contagem.
Catálogo de violações
Seção intitulada “Catálogo de violações”Os nomes são os que o ac policy, o ac_kick_on e o setAnticheatPolicy aceitam. Padrão é a ação quando nada a sobrescreve, e limite é quantas ocorrências dentro da janela são necessárias para disparar.
movement
Seção intitulada “movement”Posição, velocidade e pose de um jogador a pé. Política padrão: log, 30 em 10s.
| Violação | Padrão | Limite | Janela | Dispara quando |
|---|---|---|---|---|
movement-speed | log | 30 | 10s | A velocidade horizontal no chão, medida entre duas posições reportadas, passa do ac_player_max_speed. A amostra é recusada e o jogador é puxado de volta à última posição aceita. |
movement-teleport | log | 30 | 10s | O salto entre duas posições passa do limite de teleporte. |
movement-out-of-bounds | log | 30 | 10s | Posição fora do ac_world_bound, ou fora da faixa de Z. |
movement-not-finite | log | 30 | 10s | Coordenada NaN ou infinita. |
movement-bad-stat | log | 30 | 10s | Vida ou colete fora da faixa aceita. |
movement-not-owner | log | 30 | 10s | O peer sincronizou um elemento que não é dele. |
movement-velocity | log | 30 | 10s | Vetor de velocidade cujo módulo passa do ac_max_velocity; o vetor informado é zerado. |
movement-aim | log | 30 | 10s | Ponto de mira longe demais do jogador. |
movement-timing | warn | 2 | 60s | Pacotes de sync chegando bem mais rápido que a cadência de envio. |
movement-fly | log | 3 | 60s | Voo sustentado sem veículo nem jetpack. |
movement-climb | log | 3 | 60s | Ganho vertical incompatível com a distância horizontal percorrida. |
Tiros e dano. Política padrão: warn, 10 em 10s.
| Violação | Padrão | Limite | Janela | Dispara quando |
|---|---|---|---|---|
combat-weapon-not-granted | log | 3 | 10s | Tiro com arma que o servidor nunca deu ao jogador. |
combat-range | warn | 10 | 10s | Alvo além do alcance da arma. |
combat-rate | warn | 10 | 10s | Cadência de tiro acima do que a arma permite. |
combat-damage | warn | 10 | 10s | Dano acima do que a arma consegue causar. |
combat-no-ammo | log | 5 | 10s | Tiro sem munição. |
combat-target | warn | 10 | 10s | Alvo inválido ou inalcançável. |
combat-aim-snap | log | 10 | 10s | Mira grudando no alvo em um único frame — a assinatura clássica de aimbot. |
Com ac_validate_damage 1, o servidor também acumula o dano reportado por cada atacante em janelas de aproximadamente 1 segundo. Ao ultrapassar ac_damage_burst_cap (padrão 900.0), ele relata combat-damage; a política dessa violação continua determinando quando uma ação dispara.
vehicle
Seção intitulada “vehicle”Assentos e estado de veículo. Política padrão: warn, 10 em 10s.
| Violação | Padrão | Limite | Janela | Dispara quando |
|---|---|---|---|---|
vehicle-seat-claim | warn | 10 | 10s | Reivindica um assento que não pode ocupar. |
vehicle-seat-occupied | warn | 10 | 10s | Reivindica um assento que já tem alguém. |
vehicle-unseated-claim | warn | 10 | 10s | Sincroniza um veículo no qual não está sentado. |
vehicle-enter-denied | warn | 10 | 10s | Começou a animação de entrada depois de o servidor negar. |
vehicle-bad-state | warn | 10 | 10s | Vida ou estado fora da faixa aceita. |
vehicle-velocity | warn | 10 | 10s | Velocidade ou velocidade de giro cujo módulo passa do ac_max_velocity — o mesmo limite de envelope do lado a pé. O vetor informado é zerado. |
protocol
Seção intitulada “protocol”Tráfego malformado. É a única família que expulsa já na primeira ocorrência por padrão, porque nenhum cliente legítimo produz isso.
| Violação | Padrão | Limite | Janela | Dispara quando |
|---|---|---|---|---|
protocol-plaintext | kick | 1 | 10s | Pacote chegou sem criptografia depois do handshake. |
protocol-state-gate | warn | 8 | 10s | Pacote enviado em um estado de conexão que não o aceita. |
protocol-event-source | warn | 10 | 10s | O source informado no triggerServerEvent não é o jogador nem um filho dele. Depende do ac_strict_event_source. |
protocol-oversized | kick | 1 | 10s | Pacote acima do limite de tamanho. |
protocol-rate | kick | 1 | 10s | Pacotes acima da taxa aceita. |
protocol-malformed | kick | 1 | 10s | Pacote que falha ao ser decodificado. |
protocol-event-rate | warn | 3 | 10s | Eventos remotos disparados acima da taxa aceita. |
integrity
Seção intitulada “integrity”Respostas ao desafio de integridade. Só dispara com ac_integrity 1.
| Violação | Padrão | Limite | Janela | Dispara quando |
|---|---|---|---|---|
integrity-world-state | log | 2 | 5min | O digest do estado do mundo do cliente não bate com o do servidor. |
integrity-weapon-stats | log | 2 | 5min | O digest da tabela de armas do cliente não bate com o do servidor. |
integrity-no-report | log | 3 | 5min | O cliente não respondeu ao desafio a tempo. |
Detecção de macro e autoclicker. O cliente mede o próprio teclado e envia os números; o servidor é quem decide se aquilo é macro e o que acontece com o jogador. Política padrão: kick, 3 em 60s — nunca no primeiro relato, porque um único achado em hardware real é indício, não prova.
| Violação | Padrão | Limiar | Janela | Dispara quando |
|---|---|---|---|---|
input-macro-injected | kick | 2 | 60s | O sistema operacional marcou as teclas como sintetizadas — SendInput/keybd_event, ou seja AutoHotkey, autoclickers e ferramentas de acesso remoto. Relatado após 12 dessas teclas em 10s. |
input-macro-timing | kick | 3 | 60s | Uma sequência de teclas numa mesma tecla uniforme demais para ser uma mão: 16 amostras cujo intervalo e tempo de pressão quase não variam. |
O detalhe escrito na trilha carrega os números por trás do relato — quantas teclas, o intervalo médio e, no input-macro-timing, a variação em torno dele.
set ac_macro 0 põe a família em ignore: o cliente continua relatando e o servidor descarta o que chega.
Modos de aplicação
Seção intitulada “Modos de aplicação”As políticas escalonadas de gameplay e integridade começam em modo de observação. Há duas chaves opcionais para elevá-las durante a inicialização; violações de protocolo mantêm suas ações padrão, inclusive os kick imediatos da tabela acima:
| Convar | Políticas aplicadas quando ativada |
|---|---|
ac_enforce | movement-fly, movement-climb e movement-teleport: kick em 4/60s; combat-weapon-not-granted: kick em 3/10s; vehicle-velocity: kick em 10/10s. |
ac_integrity_enforce | integrity-world-state e integrity-weapon-stats: kick em 3/5min; integrity-no-report: kick em 2/5min. |
ac_macro | Ligado por padrão. Colocar 0 põe input-macro-injected e input-macro-timing em ignore. |
ac_integrity_enforce só tem efeito prático quando ac_integrity 1 também está ativo. ac_kick_on é aplicado depois desses modos e força as violações listadas a kick, preservando o limite atual; apesar do nome, o atalho não redefine o limite para 1.
Modo sombra
Seção intitulada “Modo sombra”set ac_shadow 1 — ou ac shadow on no console — mantém todo o fluxo rodando: as violações são contadas, gravadas na trilha e exibidas no console conforme a tabela de ações, e o onPlayerAnticheatViolation continua disparando. O modo sombra não muda qual ação dispara, então uma violação com ação log continua fora do console aqui também. Só a desconexão é suprimida, e a linha de kick vem marcada com [shadow].
É assim que se coloca uma política mais rígida no ar: liga o modo sombra, roda por alguns dias, lê a trilha e só então desliga.
A trilha
Seção intitulada “A trilha”Cada janela de contagem é anexada ao arquivo em ac_trail (padrão logs/anticheat.log) uma vez, no instante em que cruza o limite. Ocorrências posteriores na mesma janela não geram novas linhas. O formato é separado por tabs:
timestampMs elementId família violação contagemNaJanela contagemTotal ação detalhe1754390112345 42 combat combat-aim-snap 10 37 log target 91 delta 178degO arquivo é aberto em modo append e sofre flush a cada linha, então sobrevive a um crash. ac_trail "" desativa.
Desafio de integridade
Seção intitulada “Desafio de integridade”Com ac_integrity 1, o servidor envia periodicamente um nonce para cada jogador. O cliente calcula o hash da tabela de armas ou do estado do mundo que tem carregado e devolve o digest; o servidor compara com o digest que ele calcula a partir do próprio estado.
Os dois tipos de desafio se alternam por jogador, então ac_integrity_interval 60 significa que cada tabela é verificada a cada 2 minutos. Um jogador que nunca responde levanta integrity-no-report.
Os desafios ficam retidos por um instante depois de qualquer mudança no mundo, para que um setGravity em trânsito não seja lido como divergência.
Isenções
Seção intitulada “Isenções”Um jogador pode ser dispensado de famílias inteiras — útil para um admin em noclip, ou um membro da equipe testando um veículo em velocidade impossível.
-- dispensa as famílias de gameplay: movement, combat e vehiclesetPlayerAnticheatEnabled(admin, false)
-- dispensa apenas o necessáriosetPlayerAnticheatEnabled(admin, false, "movement,vehicle")
-- de volta ao normalsetPlayerAnticheatEnabled(admin, true)A dispensa também cobre o envelope de sincronização: as amostras de um jogador isento nunca são recusadas, então o admin em noclip acima não é puxado de volta pelo ac_player_max_speed nem pelos limites de velocidade. Apenas movement-not-finite e movement-not-owner continuam recusando a amostra mesmo com isenção — nenhuma dispensa aceita coordenada NaN ou elemento roubado.
Nomes aceitos: movement, combat, vehicle, protocol, integrity, input, mais os atalhos gameplay (movement + combat + vehicle) e all.
Como ajustar
Seção intitulada “Como ajustar”Pelo server.cfg
Seção intitulada “Pelo server.cfg”Lido apenas na inicialização. Veja a referência das convars.
set ac_enabled 1set ac_shadow 0set ac_enforce 0set ac_kick_on "protocol-plaintext,vehicle-seat-occupied"O ac_kick_on é um atalho: ele muda a ação das violações listadas para kick, preservando o limite que já estiver configurado para cada uma.
Pelo console
Seção intitulada “Pelo console”Vale imediatamente e dura até o próximo restart. Veja ac.
ac statusac violations Kalelac policy combat-aim-snap kick 5 10000Pelo Lua
Seção intitulada “Pelo Lua”| Função | O que faz |
|---|---|
setAnticheatPolicy | Muda a ação, o limite e a janela de uma violação. |
getPlayerAnticheatViolations | Lê a ficha de um jogador. |
setPlayerAnticheatEnabled | Concede ou remove uma isenção. |
isPlayerAnticheatEnabled | Lê a isenção atual. |
E o evento que dá a você a palavra final:
addEventHandler("onPlayerAnticheatViolation", root,function(violacao, id, familia, contagem, detalhe) if familia == "movement" and isPlayerStaff(source) then cancelEvent() -- nenhuma punição para esta endend)