Entrada do servidor

9

Atualmente no meu jogo, o cliente nada mais é do que um renderizador. Quando o estado de entrada é alterado, o cliente envia um pacote ao servidor e move o player como se estivesse processando a entrada, mas o servidor tem a palavra final na posição.

Isso geralmente funciona muito bem, exceto por um grande problema: cair das arestas. Basicamente, se um jogador estiver caminhando em direção a uma borda, digamos um penhasco, e parar logo antes de sair da borda, às vezes um segundo depois, ele será teleportado para fora da borda. Isso ocorre porque o pacote "Parei de pressionar W" é enviado depois que o servidor processa as informações.

Aqui está um diagrama de atraso para ajudá-lo a entender o que quero dizer: http://i.imgur.com/Prr8K.png

Eu poderia apenas enviar um pacote "W Pressed" a cada quadro para o servidor processar, mas isso pareceria uma solução dispendiosa em largura de banda.

Qualquer ajuda é apreciada!

Thomas
fonte

Respostas:

5

Embora o servidor tenha a palavra final sobre a posição, ele deve fazer isso verificando e verificando o que o cliente envia como entradas e posição. Digo isso porque o que você está fazendo é mover o player imediatamente e a expectativa que cria no seu código é que o cliente esteja na posição real.

Você acha que geralmente funciona bem, mas não é. Nota lateral: você diz que seu cliente nada mais é do que um renderizador e, em seguida, concede-lhe prontamente controle local para se movimentar sem as mensagens do servidor. Você não pode ter as duas coisas: espere o servidor pedir para você se mover ou assuma algum controle sobre sua posição e use o servidor para verificar truques.

Percebo que suas respostas estão chegando a um segundo inteiro? Essa latência é de 500ms, ridiculamente grande para qualquer tipo de jogo de ação. Tente descobrir por que essa reviravolta está demorando tanto; pode ser qualquer coisa, desde filas de comando que não são tratadas prontamente até largura de banda inundada ou até demônios, causando muitos pacotes perdidos.

O que eu acho que deveria acontecer é que

client sends a move + position update
server gets it t+latency time later
server verifies and sends out info to all clients
client receives this at (t+latency + latency)

A parte complicada aqui é que, se um cliente recebe uma mensagem sobre si mesmo, deve ignorá-la, a menos que essa mensagem seja algo como "movimentação inválida, vá para XYZ". Se essa mensagem for para o cliente de outra pessoa sobre a qual você está obtendo informações, será necessário extrapolar o encaminhamento a tempo, para que pareça estar onde será.

Patrick Hughes
fonte
O cliente não envia sua posição; simplesmente prediz / interpola. É por isso que cai das bordas quando pensa que está na borda. Além disso, não vejo onde eu disse que o atraso foi de 1 segundo, é mais como 8ms (teste local) a 100ms (pela Internet). Eu disse que o jogador estava se atrasando mais tarde porque periodicamente envio atualizações completas de posições. Estou correto ao entender que devo enviar a posição que o cliente acha que deveria ser, juntamente com as teclas que foram pressionadas, e o servidor deve verificar se é possível?
Thomas
"às vezes, um segundo depois, ele será teletransportado" implicava em grandes atrasos, que é de onde eu tirei o tempo. Para um jogo de ação responsivo, sim, o cliente joga e o servidor fica atrasado no tempo e informa ao cliente se ele fez algo ilegal. Você notará que, nos jogos multiplayer online, você vê outras pessoas trocando de posição (aquelas que vêm do servidor), enquanto sua própria posição raramente muda de correções diretas no servidor. Outras pessoas vêem você mudar de posição, etc ...
Patrick Hughes
Ainda não foi possível fazer com que o player caísse no servidor? A menos que eu envie um pacote a cada quadro, o servidor ainda pode pensar que o player está se movendo por cerca de 32ms. (Apenas envio pacotes a cada três quadros). Ou você está sugerindo que eu não simule nenhuma entrada no servidor, mas apenas verifique se a posição está dentro dos limites da entrada pressionada?
Thomas
Como o servidor corrige apenas os movimentos inválidos relatados pelo cliente, ele nunca enviaria um "você caiu do penhasco", a menos que o próprio cliente passasse pela borda. Nesse ciclo de feedback, é o servidor que se corrige da visão de mundo do cliente e de seu lugar nele. O movimento parecerá nítido e responsivo ao jogador. Outras ações, como interagir com objetos do mundo, envolverão a espera do servidor para informar ao cliente o que aconteceu, clique em uma caixa e aguarde resposta, mas estamos falando apenas de movimento aqui.
Patrick Hughes
Parece muito com o que estou fazendo atualmente; enviando uma posição para o servidor e solicitando que o servidor valide se o jogador poderia ter se mudado para essa posição. Essa parece ser uma abordagem mais heurística e, na minha opinião, não seria tão eficaz quanto decidir o servidor, ponto final. O envio de registros de data e hora com cada pacote funcionaria? Eu acho que isso iria erradicar o problema. Acredito que Halo e jogos que usam o mecanismo Source usem isso.
Thomas
0

Entendo sua pergunta como:

O servidor recebe um pacote quando começo a pressionar o botão 'encaminhar' e outro pacote quando finalmente soltei o botão 'encaminhar'. Portanto, o movimento real no servidor inicia e termina cerca de 100 milissegundos 'muito tarde' no jogo real versus o que o jogador está expressando no lado do cliente. Portanto, se o jogador quiser mover 10 segundos, ele pode acabar movendo 10.x segundos em vez de x >= 1online.

Essa é uma péssima estratégia de design, pois não expressa a vontade do jogador no mundo do jogo, como ele pretende, criando uma experiência de usuário bastante ruim.

A solução que eu recomendaria é enviar um pacote (sempre que possível) que indique quantas etapas o jogador executou e em que direção. O servidor atualiza o mundo do jogo com o novo local do jogador, se ele passar na verificação de correção. Assim, o jogador pode se mover com grande precisão e evitar cair de bordas altas.

A alternativa seria lembrar as posições do jogador no segundo passado e corrigir a posição em retrospecto ao momento em que o botão foi solto. Parece que isso criaria o efeito elástico dos velhos tempos. (Apenas por um motivo diferente)

Então, basicamente, você precisaria enviar um pacote de qual botão foi pressionado e qual foi a hora real do jogo em que o botão foi pressionado e, posteriormente, qual botão foi liberado e a que hora exata.

AturSams
fonte
Como disse a Patrick, acho que a solução seria mais uma abordagem heurística; em vez de o servidor ser "The Man", o servidor verifica a validade dos dados do cliente. É claro que isso precisará criar uma margem de manobra para que o atraso ou outros problemas de rede não criem falsos positivos.
Thomas