Comment synchroniser les horloges sur le réseau pour le développement de jeux?

10

J'écris un jeu qui a beaucoup d'aspects temporels. J'utilise le temps pour aider à estimer les positions des joueurs lorsque les blocages et les paquets du réseau ne passent pas (et le temps entre la réception des paquets et non). C'est un jeu de type pacman dans le sens où un joueur choisit une direction et ne peut pas arrêter de bouger, donc ce système a du sens (ou du moins je pense que oui).

J'ai donc deux questions: 1) Comment synchroniser les horloges des jeux au début car il y a un retard dans le réseau. 2) Est-il correct de ne pas les synchroniser et de simplement supposer qu'ils sont les mêmes (mon code est indépendant du fuseau horaire). Ce n'est pas un jeu super compétitif où les gens changeraient leurs horloges pour tricher, mais quand même.

Le jeu est en cours de programmation en Java et Python (développement parallèle en tant que projet)

sinθ
la source
7
chercher ntp
ratchet freak
5
Je suis sûr que cette question est déjà couverte sur gamedev.stackexchange.com, ou du moins elle y appartient.
congusbongus
1
@CongXu: Je n'en suis pas si sûr. Bien que cette tâche soit généralement effectuée pour les jeux, elle n'est pas intrinsèquement spécifique au développement de jeux. De nombreux autres systèmes distribués nécessitent une horloge synchronisée.
Jan Hudec
2
Avez-vous déjà essayé d'utiliser l'option IPv4 TIMESTAMP? Plus d'informations sont à linux.die.net/man/7/socket de là à linux.die.net/man/3/cmsg et puis un petit programme d'exemple à pdbuchan.com/rawsock/rawsock.html le dernier avant le Section IPv6.
ott--
2
Les jeux (applications) ne doivent pas toucher l'horloge système.
Rétablir Monica - M. Schröder

Réponses:

9

Je pense que ce n'est certainement pas OK de synchroniser l'horloge dans le système . L'utilisateur ne s'attend pas à ce que vous touchiez les paramètres du système et de nombreux systèmes ne vous le permettront même pas.

Tout ce dont vous avez besoin est d'avoir une corrélation pour convertir l'horodatage de l'horloge d'un côté à l'horloge de l'autre côté. D'un autre côté, vous avez besoin que cette corrélation soit assez précise, disons au moins au centième de seconde, si vous voulez l'utiliser pour prédire les positions des joueurs. L'horloge système ne sera jamais aussi bien corrélée entre des machines aléatoires. Vous devez donc établir la corrélation vous-même, en utilisant une variation sur le thème NTP , probablement intégré dans vos autres messages pour conserver la bande passante du réseau.

L'idée de base pourrait être qu'avec chaque paquet que vous avez envoyé, vous avez envoyé l'horodatage et le numéro de séquence et l'horodatage lorsque vous avez reçu le dernier paquet de l'autre côté. À partir de cela, vous calculez l'aller-retour: Par exemple, si le paquet Q dit qu'il a été envoyé à 1000 et que le paquet P a été reçu à 500, alors que vous avez envoyé le paquet P à 0 et que vous recevez Q à 800, l'aller-retour est (800 - 0 ) - (1000 - 500) = 300. Il n'y a aucun moyen de connaître l'assymétrie, donc vous supposez simplement que le paquet prend la moitié (150) ticks dans les deux sens. Et cet horodatage distant est en avance sur le local de 1000 - (800 - 150) = 350 ticks. L'aller-retour variera. Si vous supposez que l'horloge est raisonnablement précise, vous devez utiliser une moyenne à long terme de la corrélation.

Notez que vous ne souhaitez pas non plus utiliser l'horloge système pour l'horloge. Ils peuvent se resynchroniser à mi-chemin, vous jetant hors piste. Vous devez utiliser clock(CLOCK_MONOTONIC)sur Unix ou GetTickCountsur Windows (vous ne savez pas comment ces API sont encapsulées en Java ou Python en ce moment).


Remarque: L' SO_TIMESTAMPoption socket (voir socket (7) mentionnée par ott-- dans le commentaire sur la question) serait utile pour séparer l'effet de latence de la boucle d'événement qui reçoit les paquets. Que cela en vaille la peine dépend de la précision dont vous avez besoin.

Jan Hudec
la source
1

Comment savez-vous quelle horloge de joueur est correcte? Ce n'est pas le cas, alors utilisez une horloge de référence .

NTP est exagéré ici - vous n'avez besoin que d'une précision d'environ 1 seconde - alors utilisez rdate ou choisissez quelque chose parmi l'un des nombreux algorithmes de synchronisation d'horloge.

Si vous avez choisi une méthode, demandez à la machine de chaque joueur de prendre le temps selon cette méthode (sans changer l'horloge de son système). Quelle que soit la différence entre l'heure UTC de référence et l'heure UTC de l'horloge système des joueurs, c'est leur décalage effectif. Chaque fois que vous effectuez des calculs liés au temps, par exemple pour extrapoler des mouvements de bot ou des puces à rayons, vous tenez compte de ce décalage après avoir obtenu l'heure système. L'utilisation de l'UTC éliminera les facteurs de fuseau horaire.

JBRWilkinson
la source
1

Je soutiens deux fois que vous ne devez pas utiliser NTP ou vous approcher de l'horloge système pour cela. Si vous examinez réellement cette exigence, vous constaterez que vous avez les besoins suivants:

  • Combien de temps s'est écoulé depuis la trame précédente afin que vous puissiez avancer n'importe quel élément temporel. Cela peut être différent sur le client et le serveur si les deux coïncident à des taux différents (par exemple, vous pouvez parfois voir des serveurs qui fonctionnent à une fréquence fixe de 20 Hz (ou autre) mais des clients qui sont autorisés à fonctionner aussi vite qu'ils le souhaitent).
  • Combien de temps s'est écoulé depuis le début de la carte actuelle. Il s'agit d'un minuteur basé sur zéro (il suffit de l'initier à 0 sur le client et le serveur au démarrage) et l'heure du serveur est considérée comme "maître", donc le serveur envoie sa vue actuelle de cette heure au client pour chaque trame qui s'exécute sur le serveur. Cela peut être obtenu soit en prenant l'heure actuelle du serveur et en soustrayant l'heure à laquelle le serveur a démarré, soit en cumulant les temps par image ci-dessus. Le temps par trame côté client ci-dessus peut également être utilisé pour générer des points d'interpolation entre deux trames de serveur consécutives.
  • Un «temps de base» de référence à partir duquel tout autre temps avance; cela peut être (mais pas nécessairement pour tous les types de jeu) le même sur le client et le serveur et est initialisé au début du jeu (ou de la carte actuelle) mais jamais changé après (à moins qu'un nouveau jeu - ou une nouvelle carte - a démarré).

Il s'agit d'un plan simplifié - je n'essaie pas de traiter des problèmes tels que la latence / les paquets perdus / etc. - mais c'est le cadre de base sur lequel tout doit être basé.

Rien de tout cela ne doit s'approcher de l'horloge système ou se préoccuper de questions telles que les différents fuseaux horaires, bien que le dernier élément puisse utiliser un fuseau horaire si vous le souhaitez. L'important est que les temps réels écoulés soient mesurés à l'aide d'un minuteur haute résolution à base zéro, de sorte qu'ils soient complètement indépendants des différences de fuseau horaire. Vous voulez trouver l'heure actuelle sur le serveur? Ajoutez simplement le temps écoulé à son temps de base de référence et vous l'avez. De même pour le client.

Maximus Minimus
la source