Wie synchronisiere ich Uhren über Netzwerke für die Spieleentwicklung?

10

Ich schreibe ein Spiel, das viele zeitbasierte Aspekte hat. Ich benutze Zeit, um Spielerpositionen zu schätzen, wenn das Netzwerk blockiert und Pakete nicht durchlaufen werden (und die Zeit zwischen dem Empfang von Paketen und nicht). Es ist ein Pacman-Spiel in dem Sinne, dass ein Spieler eine Richtung wählt und nicht aufhören kann, sich zu bewegen, so dass dieses System Sinn macht (oder zumindest denke ich, dass es das tut).

Ich habe also zwei Fragen: 1) Wie synchronisiere ich die Uhren der Spiele zu Beginn, da es im Netzwerk zu Verzögerungen kommt? 2) Ist es in Ordnung, sie NICHT zu synchronisieren und einfach anzunehmen, dass sie gleich sind (mein Code ist zeitzonenunabhängig). Es ist kein super wettbewerbsfähiges Spiel, bei dem die Leute ihre Uhren ändern würden, um zu betrügen, aber trotzdem.

Das Spiel wird in Java und Python programmiert (parallele Entwicklung als Projekt)

sinθ
quelle
7
Nachschlagen ntp
Ratschenfreak
5
Ich bin sicher, dass diese Frage bereits auf gamedev.stackexchange.com behandelt wird oder zumindest dort hingehört.
Congusbongus
1
@CongXu: Ich bin nicht so sicher. Während dies normalerweise für Spiele erledigt wird, ist es nicht von Natur aus spezifisch für die Spieleentwicklung. Viele andere verteilte Systeme benötigen eine synchronisierte Uhr.
Jan Hudec
2
Haben Sie bereits versucht, die IPv4-Option TIMESTAMP zu verwenden? Weitere Informationen finden Sie unter linux.die.net/man/7/socket von dort zu linux.die.net/man/3/cmsg und dann ein kleines Beispielprogramm unter pdbuchan.com/rawsock/rawsock.html, dem letzten vor dem IPv6-Abschnitt.
ott--
2
Spiele (Anwendungen) sollten die Systemuhr nicht berühren.
Monica wieder herstellen - M. Schröder

Antworten:

9

Ich denke, es ist definitiv nicht in Ordnung, die Uhr im System zu synchronisieren . Der Benutzer erwartet nicht, dass Sie die Systemeinstellungen berühren, und viele Systeme lassen dies nicht einmal zu.

Alles, was Sie brauchen, ist eine Korrelation, um den Zeitstempel von der Uhr einer Seite in die Uhr der anderen Seite umzuwandeln. Andererseits muss diese Korrelation ziemlich genau sein, etwa bis zu einer Hundertstelsekunde, wenn Sie sie zur Vorhersage der Spielerpositionen verwenden möchten. Die Systemuhr wird niemals so gut zwischen zufälligen Maschinen korrelieren. Daher sollten Sie die Korrelation selbst herstellen und dabei einige Variationen des NTP- Themas verwenden, die wahrscheinlich in Ihre anderen Nachrichten eingebettet sind, um die Netzwerkbandbreite zu schonen.

Die Grundidee könnte sein, dass Sie mit jedem Paket, das Sie gesendet haben, den Zeitstempel gesendet haben und die Sequenznummer und den Zeitstempel, als Sie das letzte Paket von der anderen Seite empfangen haben. Daraus berechnen Sie den Roundtrip: Wenn beispielsweise Paket Q angibt, dass es um 1000 gesendet wurde und Paket P mit 500 empfangen wurde, als wenn Sie Paket P mit 0 gesendet haben und Q mit 800 empfangen, beträgt der Roundtrip (800 - 0) ) - (1000 - 500) = 300. Es gibt keine Möglichkeit, die Assymetrie zu kennen. Sie nehmen also einfach an, dass das Paket die Hälfte (150) Ticks in beide Richtungen benötigt. Und dieser entfernte Zeitstempel liegt um 1000 - (800 - 150) = 350 Ticks vor dem lokalen. Die Hin- und Rückfahrt variiert. Wenn Sie davon ausgehen, dass die Uhr ziemlich genau ist, sollten Sie einen langfristigen Durchschnitt der Korrelation verwenden.

Beachten Sie, dass Sie die Systemuhr auch nicht für die Uhr verwenden möchten. Sie werden möglicherweise auf halbem Weg neu synchronisiert, was Sie aus der Bahn wirft. Sie sollten clock(CLOCK_MONOTONIC)unter Unix oder GetTickCountWindows verwenden (nicht sicher, wie diese APIs derzeit in Java oder Python eingeschlossen sind).


Hinweis: Die SO_TIMESTAMPSocket-Option (siehe Socket (7) , der von ott-- im Kommentar zur Frage erwähnt wird) ist nützlich, um den Effekt der Latenz der Ereignisschleife, die die Pakete empfängt, herauszufiltern. Ob sich die Mühe lohnt, hängt davon ab, wie genau Sie sind.

Jan Hudec
quelle
1

Woher weißt du, welche Uhr des Spielers korrekt ist? Verwenden Sie keine Referenzuhr .

NTP ist hier übertrieben - Sie benötigen nur eine Genauigkeit von ~ 1 Sekunde - verwenden Sie also rdate oder wählen Sie etwas aus einem der vielen Taktsynchronisationsalgorithmen aus.

Wenn Sie eine Methode ausgewählt haben, lassen Sie den Computer jedes Spielers die Zeit nach dieser Methode erfassen (ohne die Systemuhr zu ändern). Was auch immer der Unterschied zwischen der Referenz-UTC-Zeit und der Systemuhr-UTC-Zeit der Spieler ist, ist ihr effektiver Versatz. Jedes Mal, wenn Sie zeitbezogene Berechnungen durchführen, um beispielsweise Bot-Bewegungen oder Ray-Trace-Aufzählungszeichen zu extrapolieren, berücksichtigen Sie diesen Versatz, nachdem Sie die Systemzeit erhalten haben. Durch die Verwendung von UTC werden Zeitzonenfaktoren eliminiert.

JBRWilkinson
quelle
1

Ich stimme den Aussagen zu, dass Sie dafür kein NTP verwenden oder sich der Systemuhr nähern sollten. Wenn Sie diese Anforderung tatsächlich untersuchen, werden Sie feststellen, dass Sie die folgenden Anforderungen haben:

  • Wie viel Zeit ist seit dem vorherigen Frame vergangen, damit Sie alle zeitbasierten Dinge vorantreiben können. Dies kann auf Client und Server unterschiedlich sein, wenn beide mit unterschiedlichen Raten ticken (z. B. sehen Sie manchmal Server, die mit festen 20 Hz (oder was auch immer) ausgeführt werden, aber Clients, die so schnell ausgeführt werden dürfen, wie sie möchten).
  • Wie viel Zeit ist seit dem Start der aktuellen Karte vergangen? Dies ist ein auf Null basierender Timer (beim Start einfach auf Client und Server auf 0 setzen). Die Serverzeit wird als "Master" betrachtet, sodass der Server für jeden Frame seine aktuelle Ansicht dieser Zeit an den Client sendet das läuft auf dem Server. Dies kann erreicht werden, indem entweder die aktuelle Serverzeit genommen und die Zeit abgezogen wird, zu der der Server gestartet wurde, oder indem die oben genannten Frame-Zeiten akkumuliert werden. Die oben angegebene clientseitige Zeit pro Frame kann auch verwendet werden, um Interpolationspunkte zwischen zwei aufeinanderfolgenden Serverframes zu generieren.
  • Eine Referenz- "Basiszeit", von der aus alle anderen Zeiten fortschreiten; Dies kann (muss aber nicht unbedingt für alle Spieltypen sein) auf Client und Server gleich sein und wird zu Beginn des Spiels (oder der aktuellen Karte) initialisiert, aber danach nie mehr geändert (es sei denn, es handelt sich um ein neues Spiel - oder eine neue Karte - ist gestartet).

Dies ist eine vereinfachte Übersicht - ich versuche nicht, Probleme wie Latenz / verworfene Pakete / usw. zu behandeln -, aber es ist das Grundgerüst, auf dem das Ganze basieren sollte.

Keiner dieser Bedürfnisse in der Nähe der Systemuhr gehen oder sich mit Fragen wie unterschiedliche Zeitzonen betroffen sein, auch wenn das letzte Element kann eine Zeitzone verwenden , falls gewünscht. Wichtig ist, dass die tatsächlich verstrichenen Zeiten mit einem hochauflösenden Timer auf Nullbasis gemessen werden, sodass sie völlig unabhängig von Zeitzonendifferenzen sind. Möchten Sie die aktuelle Uhrzeit auf dem Server ermitteln? Fügen Sie einfach die verstrichene Zeit zur Referenzbasiszeit hinzu und Sie haben sie. Ebenso für den Kunden.

Maximus Minimus
quelle