Como sincronizar relógios através de redes para o desenvolvimento de jogos?

10

Estou escrevendo um jogo que tem muitos aspectos baseados em tempo. Uso o tempo para ajudar a estimar as posições dos jogadores quando a rede está parada e os pacotes não estão passando (e o tempo entre o recebimento e não do pacote). É um jogo do tipo pacman, no sentido em que um jogador escolhe uma direção e não consegue parar de se mover, de modo que o sistema faz sentido (ou pelo menos eu acho que sim).

Portanto, tenho duas perguntas: 1) Como sincronizo os relógios dos jogos desde o início, pois há um atraso na rede. 2) Não há problema em sincronizá-los e apenas assumir que eles são os mesmos (meu código é independente do fuso horário). Não é um jogo super competitivo, onde as pessoas mudam seus relógios para enganar, mas ainda assim.

O jogo está sendo programado em Java e Python (desenvolvimento paralelo como um projeto)

sinθ
fonte
7
consulta NTP
catraca aberração
5
Tenho certeza de que essa questão já foi abordada em gamedev.stackexchange.com, ou pelo menos ela pertence a ela.
congusbongus
1
@CongXu: Não tenho tanta certeza. Embora essa seja uma tarefa geralmente executada para jogos, ela não é inerentemente específica ao desenvolvimento de jogos. Muitos outros sistemas distribuídos precisam de relógio sincronizado.
precisa
2
Você já tentou usar a opção IPv4 TIMESTAMP? Mais informações está em linux.die.net/man/7/socket de lá para linux.die.net/man/3/cmsg e, em seguida, um pequeno exemplo de programa em pdbuchan.com/rawsock/rawsock.html a última antes do Seção IPv6.
ott--
2
Jogos (aplicativos) não devem tocar no relógio do sistema.
Reintegrar Monica - M. Schröder

Respostas:

9

Eu acho que definitivamente não é bom sincronizar o relógio no sistema . O usuário não espera que você toque nas configurações do sistema e muitos sistemas nem permitem.

Tudo o que você precisa é ter uma correlação para converter o registro de data e hora do relógio de um lado para o relógio do outro lado. Por outro lado, você precisa que essa correlação seja bastante precisa, digamos pelo menos até um centésimo de segundo, se você quiser usá-la para prever as posições dos jogadores. O relógio do sistema nunca estará tão bem correlacionado entre máquinas aleatórias. Portanto, você mesmo deve estabelecer a correlação, usando alguma variação no tema NTP , provavelmente incorporado em outras mensagens para economizar a largura de banda da rede.

A idéia básica pode ser que, em cada pacote enviado, você tenha enviado o carimbo de data / hora, o número de sequência e o carimbo de data e hora quando recebeu o último pacote do outro lado. A partir disso, você calcula a viagem de ida e volta: por exemplo, se o pacote Q diz que foi enviado em 1000 e o pacote P foi recebido em 500, então, se você enviou o pacote P em 0 e está recebendo Q em 800, a viagem de ida e volta é (800 - 0 ) - (1000 - 500) = 300. Não há como saber a assimetria, portanto, você assume que o pacote leva metade (150) tiques em qualquer direção. E esse timestamp remoto está à frente do local em 1000 - (800 - 150) = 350 ticks. A viagem de ida e volta varia. Se você presumir que o relógio é razoavelmente preciso, use uma média de longo prazo da correlação.

Observe que você também não deseja usar o relógio do sistema. Eles podem ser ressincronizados no meio do caminho, tirando você dos trilhos. Você deve usar clock(CLOCK_MONOTONIC)no Unix ou GetTickCountno Windows (não tenho certeza de como essas APIs estão agrupadas em Java ou Python agora).


Nota: A SO_TIMESTAMPopção socket (consulte o socket (7) mencionado por ott-- no comentário sobre a pergunta) seria útil para separar o efeito da latência do loop de eventos que recebe os pacotes. Se vale a pena o esforço depende de quão boa precisão você precisa.

Jan Hudec
fonte
1

Como você sabe qual relógio do jogador está correto? Você não precisa, então use um relógio de referência .

O NTP é um exagero aqui - você só precisa de ~ 1 segundo de precisão - então use rdate ou escolha algo de um dos muitos algoritmos de sincronização de relógio.

Quando você escolher um método, faça com que a máquina de cada jogador pegue o tempo por esse método (sem alterar o relógio do sistema). Qualquer diferença entre a hora UTC de referência e a hora UTC do relógio do sistema dos jogadores é o seu deslocamento efetivo. Sempre que você faz cálculos relacionados ao tempo para, por exemplo, extrapolar movimentos de bots ou marcadores de rastreamento de raios, você considera esse deslocamento após obter a hora do sistema. O uso do UTC eliminará os fatores de fuso horário.

JBRWilkinson
fonte
1

Eu segundas afirmações de que você não deve usar o NTP ou aproximar-se do relógio do sistema para isso. Se você realmente examinar esse requisito, descobrirá que possui as seguintes necessidades:

  • Quanto tempo se passou desde o quadro anterior, para que você possa avançar com qualquer material baseado em tempo. Isso pode ser diferente no cliente e no servidor, se os dois marcam a taxas diferentes (por exemplo, às vezes você pode ver servidores que executam a uma frequência fixa de 20Hz (ou o que seja)), mas clientes que têm permissão para executar o mais rápido que desejam.
  • Quanto tempo se passou desde o início do mapa atual. Esse é um cronômetro baseado em zero (basta iniciá-lo como 0 no cliente e no servidor quando eles são inicializados) e o horário do servidor é considerado o "mestre", para que o servidor envie sua visualização atual desse horário ao cliente para cada quadro que é executado no servidor. Isso pode ser obtido tomando o tempo atual do servidor e subtraindo o horário em que o servidor foi iniciado ou acumulando os tempos por quadro acima. O tempo por quadro do lado do cliente acima também pode ser usado para gerar pontos de interpolação entre dois quadros de servidor consecutivos.
  • Uma referência "tempo base" a partir da qual todos os outros tempos avançam; isso pode ser (mas não é absolutamente necessário para todos os tipos de jogos) o mesmo no cliente e no servidor e é inicializado no início do jogo (ou mapa atual), mas nunca é alterado depois (a menos que um novo jogo - ou novo mapa) - começou).

Este é um esboço simplificado - não tento lidar com questões como latência / pacotes descartados / etc - mas é a estrutura básica na qual tudo deve se basear.

Nada disso precisa se aproximar do relógio do sistema ou se preocupar com assuntos como fusos horários diferentes, embora o último item possa usar um fuso horário, se desejado. O importante é que os tempos reais passados ​​sejam medidos usando um timer baseado em zero de alta resolução, para que sejam completamente independentes das diferenças de fuso horário. Deseja encontrar a hora atual real no servidor? Basta adicionar o tempo decorrido ao tempo base de referência e você terá. Da mesma forma para o cliente.

Maximus Minimus
fonte