Combate validado pelo servidor, movimento previsto pelo cliente
Dois problemas que a maioria dos servidores trata como um só. A validação de dano é do servidor. O movimento não é.
Compromissos
Três coisas que este servidor não vai negociar
01
Validação de acertos no servidor
O dano é validado pelo MatchServer contra um buffer de snapshots de rewind, então um acerto é julgado contra onde o seu alvo realmente estava no momento em que você atirou, e não contra o que um peer afirma. A aplicação direta de dano entre clientes está sendo removida.
StatusEm migração
02
O K-Style não se toca
Butterfly, half-step, slash shot, reload shot, wall canceling, dash canceling. O movimento e os cancelamentos de animação continuam previstos pelo cliente, com os frame delays originais intactos. Zero latência de input adicionada, e nenhum “conserto” nos tempos de que a técnica depende.
StatusFechado
03
Um bloco de status por classe
Toda arma de uma classe carrega o mesmo dano, cadência, carregador e recarga. Dentro de uma classe só o modelo muda, então um cosmético nunca pode ser uma vantagem. Sem status por doação, sem armas custom, sem reskin com número em cima, sem item de status atrás de pagamento. Nada que você possa comprar muda uma briga.
StatusFechado
O modelo original
Na versão original, o match server cuida do lobby, da lista de salas, do stage e do placar. Ele não decide quem morre. Assim que a partida começa, os clientes conversam direto entre si por UDP, e entre as mensagens que trocam estão as que aplicam dano.
Esse projeto fazia sentido em 2006 e produz duas falhas que todo jogador de GunZ reconhece:
A conexão decide a briga. Dois clientes discordam sobre onde cada um está. Quem tem a visão de mundo mais atrasada perde acertos que viu conectar e toma acertos de ângulos que nunca aconteceram na tela dele.
Dano é uma alegação, não um fato. Se um peer diz que te acertou, o caminho original acredita na maior parte das vezes. Editar essa alegação é o cheat mais comum de GunZ e nunca teve resposta de verdade num modelo de dano peer-to-peer.
Para onde vai a autoridade
A aplicação direta de dano entre clientes está sendo removida. Em vez de um peer te dizer que você tomou dano, um cliente reporta um tiro: a arma, a origem, a direção e o timestamp do próprio cliente. O servidor decide se aquele tiro acertou alguma coisa.
A validação acontece contra o registro de mundo do próprio servidor, e não contra o que o atirador afirma sobre o alvo. Um tiro rejeitado não faz nada. Um tiro aceito gera dano que o servidor aplica e sobre o qual os dois clientes são avisados.
A diferença que importa: o cliente ainda decide quando você atira. Ele não decide mais se você acertou.
Compensação de lag
Autoridade do servidor sem compensação de lag é pior do que não ter autoridade nenhuma, porque todo jogador teria que mirar na frente do alvo de acordo com o próprio ping. Por isso o servidor guarda um histórico curto de onde cada jogador esteve: um buffer de snapshots de rewind.
Quando um tiro chega, o servidor reconstrói o mundo como o atirador viu. Ele rebobina pelo tempo de ida e volta medido do próprio atirador — o mundo que o servidor já tinha entregado para ele é tudo que saiu daqui há pelo menos uma ida e volta — e confere o tiro contra as posições que estavam na tela dele naquele instante. Posições entre dois snapshots guardados são interpoladas em vez de saltarem, então a reconstrução é suave e não picotada.
Esse rewind é medido, nunca alegado. O tiro carrega o timestamp do próprio cliente e o servidor não resolve em cima dele. Um cliente que pode escolher o momento contra o qual o tiro dele é julgado vai escolher um que o favoreça, então o timestamp fica guardado só para registrar a diferença entre o que o cliente alegou e o que o servidor mediu. A única alavanca que sobra para um cliente modificado é inflar o próprio ping atrasando os pongs, e a janela de rewind é limitada: um rewind mais para trás do que o buffer guarda é cortado em vez de extrapolado.
Rewind no servidor
Três vistas do mesmo instante: a tela do atirador, o presente do servidor, e o servidor rebobinado em uma ida e volta.
O que você viu quando atirou
Acerta
O presente do servidor, uma ida e volta depois
o alvo se moveu
Erra
O servidor, rebobinado pelo seu tempo medido
rebobinado
Acerta
O tiro é conferido contra a terceira linha, não contra a segunda. Sem o rewind todo jogador teria que mirar na frente do alvo conforme o próprio ping; com ele, o que estava na sua tela é o que o servidor testa. O rewind vem da ida e volta que o servidor mediu, nunca de um momento que o cliente pediu. A seta da segunda linha é o alvo se movendo durante essa ida e volta; na terceira é o servidor colocando ele de volta.
O que fica intocado
Movimento, cancelamentos de animação e troca de arma continuam previstos pelo cliente e com autoridade local. Nada foi inserido entre o seu input e a animação, e nada vai ser.
Isso não é um descuido para arrumar depois. O K-Style existe por causa de atrasos específicos de cancelamento de animação e de sobrescritas de estado no código original. Tratar isso como bug e consertar é exatamente como um servidor de GunZ vira outro jogo:
Butterfly — slash cancelado em dash, repetidamente.
Half-step — o dash encurtado que vem de cancelar a animação de dash cedo.
Slash shot e reload shot — as janelas de tempo da troca de arma.
Wall canceling e dash canceling — sobrescritas de estado no contato e no input.
Nada disso é validado pelo servidor, atrasado esperando confirmação, ou reescrito. Os frame delays de que essas técnicas dependem são tratados como parte da especificação.
O preço disso
Sendo honesto sobre a troca: como o movimento tem autoridade no cliente, um cliente modificado ainda consegue se mover de formas que não deveria. Isso é um problema de detecção, não de simulação, e é respondido com checagens de plausibilidade e observação, e não tirando o movimento do cliente. Entre um servidor que pega todo exploit de movimento possível e um servidor onde o butterfly funciona do jeito certo, este aqui escolhe o segundo.
Cheats
Mover o dano para o servidor elimina uma classe inteira de cheat de uma vez. Um cliente que alega dano não recebe mais nada, porque no servidor não existe mais nada lendo essa alegação.
O que sobra é assistência de mira e manipulação de movimento. Isso é tratado com checagens de plausibilidade no servidor sobre o fluxo de tiros e o de movimento, somado ao fato de que uma população competitiva pequena percebe. Não existe anticheat em nível de kernel e não vai existir.
Status
Este trabalho está em andamento e esta página descreve para onde ele vai. O estado atual, sem enfeite:
Validação de tirosImplementada no servidor para armas corpo a corpo e de longa distância, rodando na build ao vivo.
Buffer de rewindImplementado. Histórico de snapshots com reconstrução interpolada; o tamanho da janela está sendo ajustado contra latências reais.
Caminho de dano entre peersAinda presente no cliente por compatibilidade durante a migração. Em remoção.
Log de rejeiçõesImplementado, opcional. Cada teste de acerto pode escrever o resultado e o código do motivo — parede, fora de alcance, fora do cone, defendido, cadência — junto do rewind com que foi resolvido. Desligado por padrão porque um tiro de shotgun são doze linhas; ligado por partida para resolver um round contestado.
Autoridade do movimentoCliente. Sem mudanças, e sem previsão de mudar.