Counter-Strike16.06.2005, Joerg
Counter-Strike

Special: Die Netzwerktechnik der Source Engine

Vor mehreren Tagen posteten verschiedene andere CS-Seiten einen Artikel von Valve über die Netzwerktechnik der Source Engine. Hierbei wurde auf den englischen Original-Artikel verwiesen. Da nicht jeder User mit dem englischen Text etwas anfangen kann, hat sich euer Team von Counterstrike.de die Mühe gemacht den kompletten Artikel zu übersetzen und in unseren FAQs zu verewigt. Natürlich könnt ihr die Übersetzung auch hier auf der folgenden Seite lesen.

 Source Multiplayer Networking

Das Source Multiplayer Netzwerk

Übersicht

Auf der Source Engine basierende Multiplayer Spiele benutzen eine Client/Server Netzwerk Architektur. Üblicherweise ist der Server ein dedizierter Host, welcher das Spiel betreibt und für die Welt Simulation, Spielregeln und Spielereingaben zuständig ist. Ein Client ist der mit dem Server verbundene Computer des Spielers. Der Server und der Client kommunizieren miteinander indem sie sich in hoher Frequenz (20-30 Pakete pro Sekunde) kleine Datenpakete zusenden. Der Client bekommt die aktuellen Weltdaten vom Server und generiert daraus Grafik- und Audio-Ausgaben. Der Client nimmt des Weiteren Eingaben der angeschlossenen Eingabegeräte (Maus, Tastatur, Mikrofon) auf und sendet diese dem Server zur weiteren Verarbeitung. Alle Clients kommunizieren nur mit dem Server und nicht untereinander (wie es z.B. bei einer Peer-to-Peer Verbindung der Fall wäre). Im Unterschied zu einem Einzelspieler-Produkt, muss also ein Multispieler-Produkt mit einer großen Bandbreite an Problemen, der paket-basierenden Netzwerkkommunikation fertig werden.

Die Bandbreite des Netzwerkes ist limitiert. Daher kann der Server nicht jede kleine Veränderung der Weltdaten an alle Clients versenden. Stattdessen macht der Server Momentaufnahmen (Snapshots) der aktuellen Weltdaten und versendet dann diese an alle Clients. Die Datenpakte brauchen (abhängig von der Verbindungsgeschwindigkeit) eine bestimmte Zeit um vom Server zum Client und zurück zu kommen (der sogenannte Ping). Das bedeutet, die Weltdaten des Clients sind immer inaktueller als die Weltdaten des Servers. Natürlich brauchen auch die Daten des Clients eine bestimmte Zeit bis sie beim Server ankommen und bearbeitet werden können. Dazu kommt das jeder Client verschiedene Netzwerkanbindungen/-geschwindigkeiten hat. Auch abhängig von im Hintergrund laufendem Traffic (z.B. Teamspeak) und der Framerate des Clients (desto höher die Framerate desto mehr Daten). Dieser Zeitunterschied zwischen den Clients und dem Server verursacht natürlich logische Probleme, die sich bei zunehmender Netzwerk Latenz vergrößern. In rasanten Action Spielen kann schon eine Verzögerung von wenigen Millisekunden ein stockendes ("laggy") Spielgefühl verursachen. Dies macht es auch schwierig andere Spieler zu treffen, oder mit beweglichen Objekten zu interagieren. Neben Limitierungen der Bandbreite und der Netzwerk Latenz, kann es auch passieren das Datenpakete vom Server zum Client, oder umgekehrt nicht ankommen.

Um mit all diesen Belangen der Netzwerkkommunikation fertigzuwerden, benutzt die Source Engine verschiedene Techniken. Mit diesen können verschiedene Probleme behoben, oder zumindest weniger sichtbar für den Client gemacht werden.

 

Basis Netzwerk
Objekt Interpolation
Eingabe Voraussage
Lag Kompensation
Net Graph

                                            

Basis Netzwerk

Der Server emuliert das Spiel in separaten Zeitschritten, genannt "ticks". Der Standard sind 66 ticks pro Sekunde, diese kann aber bei Modifikationen selbst spezifiziert werden. Zum Beispiel benutzt Counter Strike:Source eine niedrigere tickrate von 33 ticks pro Sekunde, um die CPU-Auslastung des Servers zu vermindern. Bei jedem tick bearbeitet der Server ankommende Client-Kommandos, lässt diese physisch simulieren, überprüft die Spielregeln und bringt alle Objektdaten auf den neuesten Stand. Nach der Simulation entscheidet der Server welcher Client ein Update der Weltdaten benötigt und macht falls nötig eine Momentaufnahme der aktuellen Weltdaten. Eine höhere tickrate erhöht die Präzision der Simulation, braucht aber wesentlich mehr CPU-Leistung und Bandbreite von Server und Client. Der Server-Administrator kann die tickrate mit dem Parameter -tickrate xx verändern. Diese Änderung wird aber nicht empfohlen, da hierduch die Modifikation nicht mehr so wie vorgesehen arbeiten kann.

Üblicherweise haben Clients eine limitierte Bandbreite. Im schlimmsten Falle kann ein Client mit einer Modemverbindung nicht mehr als 5-7 KB/Sek empfangen. Wenn der Server jetzt versuchen würde die Updates in einer höheren Datenrate zu versenden, wäre ein Datenverlust unvermeidlich. Deswegen muß der Client dem Server seine verfügbare Bandbreite mit der Variablen "rate" in bytes pro Sekunde angeben. Dies ist die wichtigste Netzwerk-Variable für Clients und muß für einen optimalen Datenfluss korrekt gesetzt werden. Der Client kann eine bestimmte Menge von Momentaufnahmen durch Änderung der Variablen "cl_updaterate" anfordern (Standard 20). Der Server wird aber niemals mehr Updates senden als simulierte ticks. Auch wenn durch die Höhe der Anforderung das Limit der Client rate überschritten wird, werden die Daten nicht gesendet. Server-Administratoren können das Datenvolumen mit den Variablen "sv_minrate" und "sv_maxrate" (in bytes pro Sekunde) limitieren. Auch die rate der Momentaufnahmen kann mit "sv_minupdaterate" und "sv_maxupdaterate" (jeweils in snapshots pro Sekunde) festgelegt werden.

Der Client erzeugt User Kommandos durch das Abfragen der Eingabegeräte mit der gleichen tickrate auf der der Server läuft. Grundsätzlich ist ein User Kommando eine Momentaufnahme (snapshot) des derzeitigen Statutes von Tatstatur und Maus. Aber statt bei jedem Kommando ein neues Paket zu senden, sendet der Client eine bestimmte Anzahl von Paketen pro Sekunde (Standard 30). Das bedeutet das 2 oder mehr User Kommandos im gleichen Paket versendet werden. Clients können die Kommandorate mit der Variablen "cl_cmdrate" erhöhen. Dies verbessert die Ansprechempfindlichkeit, benötigt aber auch eine höhere Bandbreite zum versenden.

Die Spieledaten werden per Delta Kompression verkleinert um die Netzwerkauslastung zu verringern. Das bedeutet, dass der Server nicht jedes Mal eine komplette Momentaufnahme der Welt versendet, sondern stattdessen nur die Daten, die sich seit dem letzten Snapshot verändert haben (einen sogenannten delta snapshot). Mit jedem Paket-Versand zwischen Client und Server werden die Datenpakete numerisch quittiert, um einen zeitlich korrekten Ablauf zu gewährleisten. Komplette (non-delta) Momentaufnahmen werden nur beim Spielstart versendet, oder wenn bei einem Client ein großer Paketverlust für mehrere Sekunden auftritt. Clients können eine komplette Momentaufnahme mit der Variablen "cl_fullupdate" anfordern.

Ansprechempfindlichkeit oder die Zeit zwischen User-Eingabe und der sichtbaren Aktion in der Spielwelt, werden von vielen Faktoren beeinflusst. Inklusive der Server/Client CPU-Auslastung, der Simulationstickrate, der Datenrate und den snapshot Einstellungen, aber am meisten von der Transferzeit der Datenpakete (Ping). Die Zeit die zwischen dem Versand eines Userkommandos vergeht bis dieses vom Server empfangen wird, nennt man Latenz, Ping oder round trip time. Niedrige Latenz ist ein maßgeblicher Vorteil in einem Online-Multiplayer-Spiel. Techniken wie Vorausberechnung (prediction), oder Lagkompensierung versuchen diesen Vorteil zu minimieren, um einen fairen Spielablauf für Spieler mit schlechteren Netzwerkanbindungen zu gewährleisten. Ein optimieren der Netzwerkeinstellungen kann ein besseres spielen möglich machen, wenn die erforderliche CPU-Leistung und Bandbreite vorhanden sind. Wir empfehlen die Standard Einstellungen, da Änderungen auch durchaus negative Effekte haben können.

 

Übersicht
Objekt Interpolation
Eingabe Voraussage
Lag Kompensation
Net Graph

                 

Objekt Interpolation (Entity Interpolation)

In den Standardeinstellungen erhält der Client ca. 20 Momentaufnahmen pro Sekunde. Wenn die Objekte (Entitys) nur an dieser Stelle dargestellt werden würden, an denen sie zuvor vom Server festgestellt wurden, würden die Animationen abgehackt und rappelig aussehen. Verlorene Pakete würden des Weiteren merkbare Störimpulse hervorrufen. Der Trick um dieses Problem zu beheben ist es, beim rendern der Positionen und Animationen in der Zeit zurückzugehen. So können die Positionen zwischen zwei Momentaufnahmen flüssig dargestellt werden. Diese Technik nennt sich "client side entity Interpolation" und wird mit der Variablen "cl_interpolate 1" festgelegt. Mit 20 Momentaufnahmen pro Sekunde kommt also ca. alle 50 Milisekunden ein neues Update. Wenn die Client Renderzeit also 50 Millisekunden nach hinten gesetzt wird, können Objekte immer zwischen der letzten Momentaufnahme und der Momentaufnahme davor interpoliert werden. Die Source Engine bearbeitet die Objekt Interpolation mit einer 100 Millisekunden Verzögerung ("cl_interp 0.1"). Auf diesem Wege sind immer 2 gültige Momentaufnahmen vorhanden, auch wenn mal eine Momentaufnahme verloren geht. In der folgenden Grafik haben wir diesen Verlauf dargestellt.

Die letzte Momentaufnahme wurde bei tick 344 bzw. 10.30 Sekunden empfangen. Die Client Zeit erhöht sich basierend auf dieser Momentaufnahme und der Client Framerate. Wenn ein neuer Video Frame gerendert wird, ist die Render-Zeit die derzeitige Client Zeit 10.32, minus der Verzögerung der Sicht Interpolation von 0.1 Sekunden. Das wären in unserem Beispiel 10.22 und alle Objekte und Animationen nutzen den korrekten Bruchteil zwischen den Momentaufnahmen 340 und 342.

Da wir eine Interpolationsverzögerung von 100 ms haben, würde die Interpolation auch arbeiten wenn die Momentaufnahme 342 durch Datenverlust fehlt. Dann könnten 340 und 344 für die Interpolation genutzt werden. Wenn mehr als eine Momentaufnahme pro Paket fehlt, kann die Interpolation nicht mehr perfekt arbeiten da ihr die Momentaufnahmen aus dem Speicher (history buffer) fehlen. In diesem Falle benutzt der Renderer die Extrapolation (cl_extrapolate 1) und versucht in einer simplen, linearen Vorausberechnung, basierend auf den Daten aus dem history buffer eine Darstellung. Die Extrapolation wird nur für einen Datenverlust von 0.25 Sekunden erstellt (cl_extrapolate_ammount). Nach dieser Zeit wären die Vorhersage Fehler zu groß.

Die Objekt-Interpolation verursacht einen konstanten Sicht-Lag von 100 ms. Selbst wenn ihr auf einem so genannten "Listenserver" (Server und Client auf dem gleichen PC) spielt. Wenn ihr also die Variable "sv_showhitboxes" benutzt, werden die Spieler Hitboxen in der Server-Zeit dargestellt, das bedeutet, sie sind dem gerenderten Spieler Modell um 100 Ms voraus. Das bedeutet aber nicht, dass ihr euer Aiming verändern müsst um andere Spieler zu treffen, da die serverseitige Lag-Kompensation die Client Objekt Interpolation kennt und diesen Fehler korrigiert. Wenn ihr die Interpolation auf einem listen Server mit der Variablen "cl_interpolate 0" abschaltet, seht ihr die Hitboxen genau auf den Spieler-Modellen aber Animationen und sich bewegende Objekte werden dadurch sehr unansehnlich.

 

Übersicht
Basis Netzwerk
Eingabe Voraussage
Lag Kompensation
Net Graph

                    

Eingabe Voraussage

Nehmen wir an ein Spieler hat eine Netzwerk Latenz von 100 Ms und bewegt sich nach vorne. Die Information über die Betätigung der "+forward" Taste wird in einem User-Kommando gespeichert und zum Server gesendet. Dort wird das Kommando mit dem Bewegungs-Code bearbeitet und der Charakter des Spielers bewegt sich in der Spielwelt nach vorne. Diese Änderung der Spielewelt wird an alle Clients mit der nächsten Momentaufnahme versendet. So würde der Spieler seine eigene Bewegung mit einer Verzögerung von 100 Ms sehen. Diese Verzögerung bezieht sich auf alle Spieleraktionen wie Bewegung, schiessen usw. und wird bei höherer Latenz noch schlechter.

Eine Verzögerung zwischen der Eingabe des Spielers und dem daraus resultierenden Feedback erzeugt ein komisches und unnatürliches Spielgefühl. Es macht es dann schwierig, sich präzise zu bewegen und zu zielen. Die clientseitige Eingabe Voraussage (cl_predict 1) ist ein Weg diese Verzögerung zu entfernen um ein direktes Spielgefühl zu ermöglichen. Anstatt auf das Update der neuen Position vom Server zu warten, berechnet der Client einfach die Ergebnisse seiner eigenen User-Kommandos. Dafür benutzt er exakt die gleichen Codes und Regeln die der Server für diesen Prozess benutzen wird. Nachdem die Vorhersage beendet ist, wird sich der Spieler schon in der neuen Umgebung befinden während ihn der Server noch an der alten Position sieht.

Nach 100 Ms erhält der Client die Momentaufnahme des Servers. Diese enthält die Änderungen, basierend auf dem zuvor gesendeten Userkommando welches der Client gerade selbst vorhergesagt hat. Nun vergleicht der Client die Serverposition mit seiner vorhergesagten Position. Wenn diese voneinander abweichen ist eine Vorhersage-Fehler aufgetreten. Das zeigt an, dass der Client keine korrekten Informationen über andere Objekte und seine Umgebung hatte als er das User Kommando ausführte. Der Client muß nun die eigene Position korrigieren, da letztendlich der Server bestimmt wo sich welches Objekt befindet. Mit der Variablen "cl_showerror 1" kann der Client sehen wann Vorhersage Fehler auftreten, Korrekturen dieser Fehler können sich durch Bildsprünge bemerkbar machen. Um diesen Effekt abzumildern werden die Vorhersage Fehler schrittweise in einem kurzen Zeitraum (cl_smoothtime) behoben. Das Smoothing kann mit der Variablen "cl_smooth 0" abgestellt werden.

Die korrekte Vorhersage des Verhaltens eines Objekts kann nur dann funktionieren wenn der Client die gleichen Regeln benutzt und von der gleichen Beschaffenheit wie der Server ausgeht. Das ist üblicherweise nicht der Fall da der Server mehr interne Informationen über die Objekte hat als die Clients. Clients sehen nur einen kleinen Teil der Spielwelt und bekommen gerade genug Informationen um Objekte zu rendern. Daher funktioniert die Vorhersage nur für die eigene Spielfigur und die von ihr kontrollierten Waffen. Eine genaue Vorhersage über das Verhalten anderer Spieler oder von interaktiven Objekten ist dem Client in diesem Moment nicht möglich.

 

Übersicht
Basis Netzwerk
Objekt Interpolation
Lag Kompensation
Net Graph

               

Lag Kompensation

Sagen wir, ein Spieler schießt bei der Client Zeit 10.5 auf ein Ziel. Die Information wird in ein User-Kommando gepackt und an den Server versendet. Während das Datenpakt noch unterwegs ist, fährt der Server mit der Simulation der Spielwelt fort und das Ziel könnte sich in eine andere Position bewegt haben. Das User-Kommando trifft bei Server Zeit 10.6 ein und der Server würde den Treffer nicht registrieren, obwohl der Spieler exakt auf das Ziel geaimt hat. Dieser Fehler wird durch die serverseitige Lag Kompensation behoben (sv_unlag 1).

Das Lag Kompensations System behält eine History von allen kürzlich eingenommenen Positionen der Spieler für eine Zeitspanne von 1 Sekunde (diese Variable kann mit "sv_maxunlag" geändert werden). Wird ein User-Kommando ausgeführt, sieht der Server nach wann dieses Kommando erstellt wurde. Diese Kommando Ausführungszeit wird wie folgt berechnet:

Kommando Ausführungszeit = derzeitige Serverzeit - Client Latenz - Client Sicht Interpolation

Dann bewegt der Server alle anderen Spieler auf den Punkt zurück an dem sie zur Kommando-Ausführungszeit standen. Das User-Kommando wird ausgeführt und der Treffer wird korrekt erfasst. Nach Ausführung des User-Kommandos werden die Spieler wieder auf ihre Original-Positionen zurückgesetzt. Auf einem listen Server könnt ihr mit der Variablen "sv_showimpacts 1" den Unterschied zwischen Client- und Serverhitbox sehen.

Dieser Screenshot wurde auf einem Listen-Server mit 200 Ms Lag aufgenommen (hierbei wurde net_fakelag verwendet), kurz nachdem der Server den Treffer bestätigt hat. Die rote Hitbox zeigt die Zielposition des Clients vor 100 Ms. Seitdem hat sich das Ziel nach links weiterbewegt, während das User-Kommando zum Server unterwegs war. Nach der Ankunft des User-Kommandos stellte der Server die Zielposition (blaue Hitbox) wieder her, basierend auf der Kommando-Ausführungszeit. Der Server verfolgt den Schuß und bestätigt den Treffer (der Client sieht Blut Effekte). Client und Server Hitboxen stimmen aufgrund von Vorhersage-Fehlern nicht genau überein. Selbst eine kleine Differenz von wenigen Millisekunden kann eine Fehlberechnung von einigen cm bei sich schnell bewegenden Objekten hervorrufen. Die Multiplayer Treffer-Erkennung ist nicht auf den Pixel perfekt und hat bekannte Präzisionslimitierungen basierend auf der tickrate und der Geschwindigkeit der sich bewegenden Objekte. Eine Erhöhung der tickrate verbessert die Präzision der Treffer-Erkennung, braucht aber mehr CPU-/Speicherleistung und Bandbreitenkapazität für den Server und Clients.

Die Frage taucht auf, warum die Trefferberechnung auf dem Server so kompliziert ist durch Spielerpositionen zurückversetzen und arbeiten mit Vorhersage-Fehlern während der Treffer-Erkennung. Dies könnte doch von Client-Seite wesentlich einfacher gemacht werden und mit pixel-genauer Präzision. Der Client würde einfach dem Server mit einer Treffer-Durchsage mitteilen das und wo ein Spieler getroffen wurde. So einfach können wir es uns nicht machen weil der Server bei solch wichtigen Entscheidungen den Clients nicht vertrauen kann. Selbst wenn der Client sauber und per VAC geschützt ist, könnten die Datenpakete von einem 3ten PC auf dem Weg zum Server modifiziert werden. Diese Cheat-Proxies könnten Treffer-Durchsagen in die Pakete bringen ohne das dies von VAC erkannt wird (eine "man-in-the-middle" Attacke).

Netzwerk Latenz und Lag Kompensation können Paradoxa erschaffen die zur realen Welt unlogisch erscheinen. Zum Beispiel könnt ihr von einem Angreifer getroffen werden den ihr nicht mal mehr seht, weil ihr schon längst in Deckung seid. Was passiert ist, ist ganz einfach das der Server eure Hitbox in der Zeit zurückversetzt hat, als ihr für den Gegner noch sichtbar gewesen seid. Diese Unstimmigkeit kann aufgrund der relativ langsamen Geschwindigkeit der Datenpakete nicht behoben werden. In der realen Welt habt ihr dieses Problem nicht, weil das Licht (die Datenpakete) so schnell unterwegs ist, das du und jeder um dich herum die Welt so sieht wie sie in diesem Moment beschaffen ist.

 

Übersicht
Basis Netzwerk
Objekt Interpolation
Eingabe Voraussage
Net Graph

                

Net Graph

Die Source Engine bietet ein paar Werkzeuge um die Verbindungsgeschwindigkeit und -Qualität des Clients zu überprüfen. Die populärste ist der Net Graph, welcher mit der Variablen "net_graph 2" gestartet werden kann. Ankommende Pakete werden mit schmalen Linien von rechts nach links dargestellt. Die Höhe jeder Linie zeigt die Größe des Datenpaketes an. Wenn eine Lücke zwischen den Linien entsteht, gab es einen Datenverlust. Die Dateien sind je nach Inhalt farbkodiert.

Die erste Linie unter dem Net Graph zeigt die FPS , also die Frames/Bilder per/pro Second/Sekunde. Die durchschnittliche Latenz (Ping) und die eingestellte Updaterate. Die zweite Linie zeigt die Größe des zuletzt angekommenen Datenpakets, die durchschnittlich ankommende Bandbreite und die erhaltenen Pakete pro Sekunde. Die dritte Linie zeigt das Gleiche für ausgehende Datenpakete (User-Kommandos).

 

Übersicht
Basis Netzwerk
Objekt Interpolation
Eingabe Voraussage
Lag Kompensation
Net Graph

©2004 by Valve Co.

(übersetzt (c) 2005 4P-M|Heuermeuer) 

          

 
0
Kommentare

Du musst mit einem 4Players-Account angemeldet sein, um an der Diskussion teilzunehmen.

Es gibt noch keine Beiträge. Erstelle den ersten Beitrag und hole Dir einen 4Players Erfolg.