Aide à l'échange de messages réseau-client et à la synchronisation d'horloge

10

je fais un jeu de physique rapide qui est un hockey sur table. Avec deux maillets et une rondelle. Le jeu fonctionne sur iPhone / iPad et je fais la partie multijoueur via GameCenter.

C'est ainsi que fonctionne le système réseau. Le client qui met en vedette la correspondance sera défini comme le serveur et celui qui accepte la demande de correspondance est le client.

Le «serveur» a la physique en cours d'exécution et la réponse est immédiate et le client a également sa physique en cours d'exécution de sorte qu'il semble fluide entre les échanges de messages. Ce que je fais en tant que serveur, c'est que j'envoie au client ma vitesse de palet et ma position et que le client ajuste sa vitesse / position de palet par rapport au serveur pour le synchroniser. Sinon, la physique se désynchronise et elle le gâche.

Lorsque la latence du réseau est bonne, en dessous de 100 ms, les résultats sont plutôt bons, j'ai un jeu jouable fluide côté client et le comportement étrange est minimum. Le problème se produit lorsque le décalage est d'environ 150 à 200 ms. Dans ce cas, il arrive que mon palet client ait déjà touché un bord et une direction inversée mais il reçoit un message de retard du serveur et il recule un peu provoquant une sensation étrange au comportement de la balle.

J'ai lu quelques trucs à ce sujet:

Exemple de réseau Pong

Cliquez sur Exemple de synchronisation

Wikipédia sur la synchronisation d'horloge

Alors, comment puis-je résoudre ce problème? Dans la mesure où j'ai lu la meilleure option que j'ai, c'est de faire une synchronisation d'horloge sur le serveur / client avec un horodatage afin que lorsque je reçois des messages de retard liés à mon horloge, j'ignore simplement alors et laisse la simulation des clients faire la emploi. Êtes-vous d'accord avec ça? Et comme j'envoie des données non fiables (UDP), je peux obtenir des messages retardés ou des messages hors service.

Si c'est la meilleure approche, comment puis-je implémenter la synchronisation d'horloge. J'ai lu les étapes mais je ne l'ai pas bien compris.

Il dit que:

  1. Le client marque l'heure locale actuelle sur un paquet de "demande de temps" et l'envoie au serveur.
  2. Dès réception par le serveur, le serveur tamponne l'heure du serveur et retourne
  3. À la réception par le client, le client soustrait l'heure actuelle de l'heure envoyée et la divise par deux pour calculer la latence. Il soustrait l'heure actuelle de l'heure du serveur pour déterminer le delta de temps client-serveur et ajoute la demi-latence pour obtenir le delta d'horloge correct. (Jusqu'à présent, cet algothim est très similaire à SNTP)
  4. Le client répète les étapes 1 à 3 cinq fois ou plus, en faisant une pause de quelques secondes à chaque fois. Un autre trafic peut être autorisé dans l'intervalle, mais doit être minimisé pour de meilleurs résultats. Les résultats des réceptions de paquets sont accumulés et triés dans l'ordre de latence la plus faible à la latence la plus élevée. La latence médiane est déterminée en choisissant l'échantillon médian dans cette liste ordonnée.
  5. Tous les échantillons supérieurs à environ 1 écart-type de la médiane sont rejetés et les échantillons restants sont moyennés à l'aide d'une moyenne arithmétique.

En suivant cet exemple, j'aurais ceci:

Imaginons que le jeu soit chargé et que mon temps client soit maintenant 0, donc j'envoie au serveur que mon temps est 0.

Le message met 150 ms pour arriver au serveur mais l'horloge du serveur a déjà démarré et a une seconde d'avance sur le client. Lorsque le serveur recevra le message, l'heure sera: 1.15 et enverra cette heure au client, sommes-nous bons? Imaginons que notre décalage soit constant à 150 ms.

Maintenant, le client reçoit l'heure 1.15 et soustrait l'heure actuelle de l'heure envoyée et divise par deux pour calculer la latence. Ce qui est: 0,3 - 0 = 0,3 / 2 -> 150 ms.

Il soustrait l'heure actuelle de l'heure du serveur pour déterminer le delta d'heure client-serveur et ajoute la demi-latence pour obtenir le delta d'horloge correct:
Heure du client: 0,3 Heure du serveur 1,15
0,3 - 1,15 = 0,85 + latence (0,15) = 1

Comment est-ce synchronisé? Qu'est-ce que je rate?

C'est ma première fois sur l'expérience multijoueur et réseau, donc je suis un peu confus.

Je vous remercie.

gmemario
la source
Bonne question. Pourriez-vous corriger: 0,3 - 1,15 soit 1,15 - 0,3?
Ciaran

Réponses:

12

L'algorithme publié était correct, mais dans votre exemple, vous oubliez le temps nécessaire au paquet serveur pour arriver au client, donc:

Server time: 1
Client time: 0
Client sends 0 to server

... 150ms to get to server  (ping is 300! not 150ms in this case. Ping is round-trip)

Server time: 1.15
Client time: 0.15
Server receives packet and sends client 1.15

... 150ms to get back to client

Server time: 1.30
Client time: 0.30
Client receives 1.15 from server

Maintenant, comme vous pouvez le voir, si le client a changé son horloge à 1,15, il serait de 0,15 derrière le serveur, c'est pourquoi vous devez ajuster le Ping (alias Round Trip Time [RTT]). Voici le calcul du temps delta complet effectué sur plusieurs étapes:

Server Time - Current Time + Ping / 2
= Server Time - Current Time + (Current Time - First Packet Time) / 2
= 1.15 (Perceived, not actual!) - 0.30 + (0.30 - 0.00) / 2
= 1.00

Cela nous donne le temps delta correct de 1,00 secondes

John McDonald
la source
Je l'obtiens, donc mon horloge client est 1,00 et le serveur est 1,30 Après avoir reçu un message du serveur, dois-je ajouter le ping pour vérifier s'il s'agit d'un message en retard ou quelque chose? Une autre chose, et si la latence change, dois-je continuer à faire ces calculs tout le temps?
gmemario
L'heure delta de 1,00 s doit être ajoutée à l'horloge actuelle pour que l'heure du client soit égale à celle du serveur. La latence change toujours, chaque paquet aura un RTT légèrement différent. Dans un court laps de temps comme dans un jeu, je ne ferais cette synchronisation de temps qu'une seule fois, le client aura une assez bonne idée de l'heure du serveur et les deux horloges devraient avancer à peu près au même rythme. La seule exception serait si vous avez reçu un paquet qui semble provenir du futur. Dans ce cas, il existe 2 solutions: 1) Effectuez une nouvelle synchronisation horaire. 2) Avancez votre horloge pour qu'elle corresponde à la future horloge
John McDonald
Ok, regardons cette situation juste pour m'assurer que je l'ai: Temps du serveur: 1s Temps du client: 0s 150ms pour arriver au serveur Temps du serveur: 1.15s Temps du client: 0.15s Le serveur envoie le client 1.15s 200ms pour arriver au client Donc, mon ping est maintenant de 350 ms. Est-ce exact? Temps du serveur: 1,35 Temps du client: 0,35 Faire les calculs: 1,15 - 0,35 + (0,35 - 0,00) / 2 Maintenant mon deltaTime = 0,975 Si j'ajoute le temps delta 0,975 à mon 0,35 j'obtiens: 1,325 Ce qui est une sorte de désynchronisation. Est-ce exact aussi?
gmemario
@Gilson, c'est exact. Si la latence des deux paquets est différente (presque garantie), le calcul du temps delta du client ne sera pas parfait. Il n'y a aucun moyen pour le client d'être parfait. Dans l'algorithme que vous avez décrit dans la question, le temps delta a été calculé plusieurs fois et il y avait une méthode pour sélectionner et faire la moyenne de ces résultats. De nombreuses méthodes de synchronisation temporelle feront quelque chose comme ça, mais elles sont généralement destinées aux serveurs critiques et de longue durée comme les bourses. Pour la précision temporelle dont vous avez besoin pour un jeu court, je pense que ce serait exagéré.
John McDonald du
@Gilson, Tant que le client a une estimation raisonnable de l'heure du serveur et que les deux horloges avancent à peu près au même rythme, vous ne devriez remarquer aucun problème. Lorsque le client ou le serveur envoie une action à l'autre côté, ils envoient leur heure locale. Du côté de la réception, le message devrait toujours être dans le passé et devra être interprété comme un événement passé. Cela signifie que vous avez besoin de toutes les informations dans le paquet, comme l'emplacement, la vitesse (amplitude + direction) et le temps. Ensuite, vous pouvez placer la rondelle ici et là, et déplacer la rondelle du passé au présent. Je suis dans le chat btw
John McDonald