somethinglikegames.de

Mein Blog über Spieleentwicklung und das Drumherum


Kategorien


Tags

lag compensation scenario

Bei Spielen, die über das Netzwerk gespielt werden, entsteht notgedrungen eine Verzögerung, die sogenannte Netzwerklatenz oder einfach nur Latenz. Dies hat zur Folge, dass jeder Spieler bei Echtzeitspielen generell eine veraltete Spielwelt angezeigt bekommt. Wie veraltet die angezeigte Spielwelt ist, hängt von der jeweiligen Latenz ab. Aus diesem Grund muss der Spieler die eigene Latenz bei kompetitiven Spielen berücksichtigen und so bspw. bei Shootern beim Vorhalten nicht nur Entfernung und Kugelgeschwindigkeit, sondern auch die eigene Latenz berücksichtigen und dementsprechend etwas weiter in die vermutete Laufrichtung des Gegners zielen. Zumindest sofern es keine Gegenmaßnahmen wie Lag-Compensation gibt.

Die Latenz ist auch der Grund, warum in den frühen 2000ern in Deutschland bestimmte Internetanbieter, welche mit Fastpath bzw. deaktiviertem Interleaving warben, besonders beliebt bei Spielern waren. Zusätzlich war ISDN oft DSL bei der Latenz überlegen, da es bei ISDN keine integrierte Fehlerkorrektur wie Interleaving gibt. Ich kann mich auch jetzt noch gut daran erinnern, wie ruckelig teilweise meine Spielerfahrung in Online-Matches bei Quake 3 Arena war. Zumal man bedenken muss, dass ich damals in einem Dorf lebte, in welchem es keine Provider mit “Latenzoptimierung” gab. Zudem lebte ich auch noch bei meinen Eltern, die kein Verständnis dafür gehabt hätten, einen Aufpreis für niedrigere Latenzen zu bezahlen. Zu guter Letzt waren meine Geschwister weitere Störfaktoren für eine niedrige Latenz.

Der Grund für diese Anekdote ist, dass Quake 3 Arena, so sehr ich es mag, keine Lag-Compensation besaß und daher eine niedrige Latenz dem Spieler beträchtliche Vorteile brachte. Wichtig ist, dass wir zwischen Client-Side-Prediction und Lag-Compensation unterscheiden. Client-Side-Prediction läuft, wie der Name bereits beschreibt, einzig auf dem Client ab und versucht, flüssigere Übergänge zwischen den Serverdaten zu schaffen, wozu es hoffentlich irgendwann auch noch einen gesonderten Artikel von mir geben wird.

Lag-Compensation

Bei Lag-Compensation handelt es sich um eine Technik, die serverseitig versucht, die Netzwerklatenzen der Spieler auszugleichen. Dafür hält der Server immer eine gewisse Historie der Spielwelt vor, damit er immer die zum Zeitpunkt der Spieleraktion aktuelle Version der Spielwelt für Berechnungen nutzen kann. Dadurch soll, wer hätte es gedacht, die Latenz/ der Lag kompensiert, also ausgeglichen werden.

Im Grunde genommen funktioniert es so, dass jeder Spiel-Client bei jeder Spieleraktion den Server auch darüber informiert, auf welchen Zeitpunkt der Spielwelt sich die Spieleraktion bezieht. Bei der Auswertung der Spieleraktion unternimmt der Server somit kleine Zeitreisen und passt seine gespeicherten Versionen der Spielwelt auch nachträglich an die Ergebnisse der Spieleraktionen an.

Damit das gelingen kann, müssen alle Netzwerknachrichten mit Zeitstempeln versehen sein, und damit diese Zeitstempel auch sinnvoll ausgewertet können, muss zwischen Client und Server auch eine gewisse Zeitsynchronisation stattfinden.
Szenario

Beispielszenario

Das klingt ja eigentlich nach einer perfekten Lösung, oder? Schauen wir uns das Ganze doch mal etwas genauer an verschiedenen Beispielen an. Für alle nun folgenden Beispiele gilt, dass sie innerhalb eines Ego-Shooters spielen. Spieler P1 hat den Kopf des gegnerischen Spielcharakters, gesteuert durch Spieler P2, im Fadenkreuz, während P2 dabei ist, mit 3 m/s in die 0,5 m entfernte Deckung zu laufen. Um es möglichst einfach zu halten, benutzen wir in den Beispielen Raycast-Waffen, was bedeutet, dass die Projektilgeschwindigkeit unendlich hoch ist und somit sofort trifft. Der Server läuft mit einer Tickrate von 60, was zur Folge hat, dass er alle 17 ms die erhaltenen Netzwerknachrichten auswertet. Um sich das Beispielszenario etwas besser vorstellen zu können, gibt es nebenstehend nochmal eine Visualisierung in bester Programmer-Art 😉.

Um dieses Thema nicht noch komplizierter zu machen, als es auch so schon ist, werden alle sonstigen Latenzen (Eingabelatenzen, Rendering-Latenzen, …) ignoriert.

Damit man in den Szenarien die Latenzen auch direkt sehen kann, sind hinter allen Aktionen drei Zeitpunkte angegeben. “Zeitpunkt Spielwelt” bezieht sich dabei auf die Version der Spielwelt, die der Server gespeichert hat. “Registrierung P1” bzw. “Registrierung P2” beziehen sich auf die Zeitpunkte, zu denen P1 bzw. P2 die Anpassungen der Spielwelt registriert haben.

Szenario 1: Spieler P1 und Spieler P2 mit ähnlichen Latenzen

Latenz P1: 40 ms; Latenz P2: 50 ms

  • P1 drückt ab, wenn der Kopf von P2 mittig im Fadenkreuz ist. Zeitpunkt Spielwelt: 1003, Registrierung P1: 1043, Registrierung P2: 1053
  • Server empfängt die Nachricht von P1 (Zeitpunkt Spielwelt: 1083) und wartet bis zum nächsten Tick.
  • Server beginnt beim nächsten Tick mit der Auswertung. Dafür geht er für die Treffererkennung zum Zeitpunkt 1003 zurück und berechnet, dass P2 getroffen wurde. Diese Information wird anschließend an P1 und P2 gesendet. Zeitpunkt Spielwelt: 1088, Registrierung P1: 1128, Registrierung P2: 1138

So weit, so gut. Wie sieht es nun für P2 aus?

  • P2 erhält die Trefferinformation. Für ihn sind 85 ms vergangen, seit P1 abgedrückt hat. Da er sich mit 3 m/s in Richtung Deckung bewegt, hat er bei sich lokal \(3\,\frac{m}{s} * 85\,\text{ms} = 0{,}255\,\text{m}\) bewegt. Er befand sich also noch nicht in Deckung und konnte getroffen werden.
  • P2 wird sich wahrscheinlich ärgern, weil er getroffen wurde, aber erkennt den Treffer als valide an.

Szenario 2: Spieler P1 mit deutlich niedriger Latenz als Spieler P2

Latenz P1: 10 ms; Latenz P2: 250 ms

  • P1 drückt ab, wenn der Kopf von P2 mittig im Fadenkreuz ist. Zeitpunkt Spielwelt: 1003, Registrierung P1: 1013, Registrierung P2: 1253

  • Server empfängt die Nachricht von P1 (Zeitpunkt Spielwelt: 1023) und wartet bis zum nächsten Tick.

  • Server beginnt beim nächsten Tick mit der Auswertung. Dafür geht er für die Treffererkennung zum Zeitpunkt 1003 zurück und bemerkt, dass von P2 noch keine Informationen für diesen Zeitpunkt vorliegen, da dieser ja durch seine hohe Latenz hinterherhinkt. Zeitpunkt Spielwelt: 1037, Registrierung P1: 1047, Registrierung P2: 1287

    Nun gibt es zwei Möglichkeiten:

    1. Der Server wartet, bis P2 bei Zeitpunkt 1003 angekommen ist, um dann die Berechnungen anzustellen. Was bedeutet, dass der Server noch 250 ms warten muss, die P2 natürlich für weitere Eingaben nutzen kann.
    • Der Server stellt dann bei seinen Berechnungen fest, dass P2 nicht getroffen wurde.
    • Da P2 auf dem Weg zur Deckung ist, läuft er die ganze Zeit in diese Richtung. Als der Server Spielwelt-Zeitpunkt 1003 an alle Spieler verschickt hat, hat Spieler P2 gerade mal Spielwelt-Zeitpunkt 753 gesehen und daher konnte der Server auch nur bedingt die richtige Position von P2 zum Zeitpunkt 1003 in der Spielwelt festlegen. Was zur Folge hat, dass er bis zum Zeitpunkt 1003 noch \(3\, \frac{m}{s} * 250\, \text{ms} = 0{,}75\, \text{m}\) zurücklegen kann und somit in Deckung ist.
    • P1 erhält kein Trefferfeedback, da P2 sich längst von seiner Position wegbewegt hat und in Deckung ist. Dieser Umstand wird auch oft als “Ping Armor” bezeichnet und sollte von P1 bei zukünftigen Schüssen berücksichtigt werden.
    1. Der Server interpoliert die bisherigen Informationen.
    • Der Server kommt zu einem ähnlichen Interpolationsergebnis, wie P1 es vorgefunden hat und registriert daher einen Treffer.
Bewusst erlebt habe ich bislang nur die erste Möglichkeit. Das heißt aber nicht, dass die zweite Möglichkeit nicht benutzt wird, aber da dadurch keinerlei Latenzen erkennbar sind, ist die Registrierung des Einsatzes schwer bis unmöglich.

Szenario 3: Spieler P1 mit deutlich höherer Latenz als Spieler P2

Latenz P1: 250 ms; Latenz P2: 10 ms

  • P1 drückt ab, wenn der Kopf von P2 mittig im Fadenkreuz ist. Zeitpunkt Spielwelt: 1003, Registrierung P1: 1253, Registrierung P2: 1013
  • Server empfängt die Nachricht von P1 (Zeitpunkt Spielwelt: 1503) und wartet bis zum nächsten Tick.
  • Server beginnt beim nächsten Tick mit der Auswertung. Dafür geht er für die Treffererkennung zum Zeitpunkt 1003 zurück und berechnet, dass P2 getroffen wurde. Zeitpunkt Spielwelt: 1513, Registrierung P1: 1763, Registrierung P2: 1523

So weit, so gut. Wie sieht es nun für P2 aus?

  • P2 erhält die Trefferinformation. Für ihn sind 510 ms vergangen, seit P1 abgedrückt hat. Da er sich mit 3 m/s in Richtung Deckung bewegt, konnte er sich lokal \(3\, \frac{m}{s} * 510\, \text{ms} = 1{,}53\, \text{m}\) bewegen. Er befand sich lokal also komplett in Deckung und hätte aus seiner Sicht eigentlich nicht getroffen werden können.
  • P2 wird sich wahrscheinlich sehr ärgern, weil er getroffen wurde, obwohl er sich bereits in Deckung befand. Im Englischen nennt man dieses Phänomen auch “bullets bending around corners”. Fühlt sich da noch jemand an den Film Wanted (2008) erinnert?
Bullet bending around corners

Geschosskurven im Film Wanted, Universal Pictures 2008

Fazit

Lag-Compensation per se ist eine interessante Technik, die meiner Meinung nach das Spielerlebnis aller Spieler in schnellen kompetitiven PvP-Spielen, bspw. Shooter, verbessern kann, wenn sie unter den richtigen Rahmenbedingungen eingesetzt wird. Dadurch wird es den Spielern ermöglicht, sich auf die eigentlichen Spielmechaniken zu konzentrieren, ohne dabei die Netzwerklatenz zu berücksichtigen. Dabei ist es aber essentiell, dass die jeweiligen Spielerlatenzen nicht zu weit auseinanderliegen, da so Spieler mit niedrigen Latenzen benachteiligt werden. Schließlich wurde Lag-Compensation entwickelt, um Latenzunterschiede auszugleichen.

Letztendlich bleibt es eine Game-Design-Entscheidung. Man muss wie so oft Pro und Contra abwägen und überlegen, ob man, durch die erhöhte Komplexität wirklich einen Mehrwert für die Spieler erhält.

Weitere Lektüre

Es gibt natürlich eine Vielzahl weiterer Artikel zu dem Thema. Die, die ich selbst für diesen Artikel als Quellen genutzt habe, sind: