Das Thema liegt mir eigentlich schon lange auf der Zunge, aber da es mit BF4 wieder mehr als aktuell ist, dachte ich mal ich bringe ein wenig Licht ins Dunkel rund um Netzwerke, und diesen ominösen Netcode der an allem Schuld ist. Oder eher warum er es meist nicht ist.
Als erstes sei gesagt, dass es hier nicht, nichtens und schon gar nicht um FPS Einbrüche geht, diese haben mit Laggs, mit denen ich mich hier beschäftigen will, wenig bis gar nichts zu tun, zudem reichen die Gründe für FPS Probleme oder Leistungseinbrüche deutlich zu weit, als das ich so ein Thema unbezahlt oder gar in einem einfachen Forenpost angehen würde Ich werfe einfach mal ein paar Stichwörter in den Raum: Pipelining, Speculative execution, Caches, Reordering und Compiler Consistency. Die Lust an FPS Diskussionen verloren? Gut, dann können wir anfangen:
Was ist ein Lag?
Unter Lags verstehen wir weithin die Verzögerung zwischen dem einspeisen von Informationen ins System bis zum ankommen bzw. auslesen beim Empfänger. Davon sind zum einen Datentransfers übers Netzwerk, aber auch zbsp. die Übertragung der Bilddaten vom PC zum Bildschirm betroffen, auch wenn letztere heutzutage in einen unbemerkbaren Bereich gerutscht sind (und immer noch nichts mit FPS zu tun haben). Im folgenden werde ich das allgemeine Verständnis des Begriffs ein wenig dehnen, ohne etwas an der Substanz der Definition zu ändern, genauer gesagt möchte ich die Verzögerung zwischen dem klicken der Maustaste und dem Feedback in Form eines Bildes beim "Empfänger" zbsp. des Schusses analysieren.
Ja aber ich hab nur 20 ms zum Server, das sollte doch nicht auffallen?
Richtig, den wenigsten wird eine Verzögerung von 20 ms auffallen. Viele würden hier wohl direkt wieder aufschreien und "Scheiß Netcode" rufen. Natürlich spielt dieser eine wichtige Rolle, im Nachfolgenden werde ich aber ein Beispiel aufzeigen, das ein wenig klarer macht dass viele der uns heute in Online-Spielen bekannten Probleme keinesfalls auf die Programmierer zurückzuführen ist.
Disclaimer: Die im folgenden benutzten Zahlen sind Schätzungs- und Erfahrungswerte, die nicht für alles und jeden zutreffen werden.
Schauen wir uns mal an was passiert nachdem man in BF4 die Maustaste klickt.
Zuerst wird der Input von der Maus als Input für die CPU über Kabel und Mainboard weitergeleitet. Von dieser Verzögerung können wir aber eigentlich getrost abstrahieren. Man sollte sich nur merken dass hier bereits Zeit vergeht.
Als nächstes muss dieser Input als Interupt vom Prozessor verarbeitet werden. Dies geschieht nicht zwingend direkt, ist meist aber recht schnell erledigt. Was nun Zeit beansprucht ist die Verarbeitung dieses Inputs in der Spielelogik, und hier kommt bereits der erste Punkt an dem ich nicht weiß, wie BF4 diesen handhabt. Üblich ist es aber, diese Inputs zur Verarbeitung des nächsten Logikupdates (im folgenden "Ticks") zu speichern und erst dann zu verwerten. Diese Updates finden in mehr oder minder regelmäßigen Zyklen ab. Ich gehe hier erst einmal von einem sehr niedrigen Wert von 20ms/tick aus. (Minecraft arbeitet in 50ms Intervallen) d.h. die Verarbeitung des Inputs dauert bis zu 20ms, ohne dass der Server auch nur etwas davon ahnt.
Nehmen wir als nächstes an dass dieser Updatezyklus sehr schnell geht, und die Info quasi sofort an den Server geschickt wird. Eigentlich würde ich hier nochmal bis zu 10 ms veranschlagen gerade da der Output auch noch von der CPU zur Netzwerkkarte use. gesendet werden muss, da ich aber wenig Ahnung davon habe was BF4 tatsächlich macht, lasse ich diesen Wert nochmal weg. Aber auch hier, merkt euch dass nochmals minimal Zeit vergangen ist.
Klingt bisher doch noch gar nicht so schlimm, oder? Ab hier wird es aber hässlich: Die Daten brauchen im Mittel 20ms zum verschicken. Leider ist das aber auch nur die halbe Wahrheit. Von diesen Informationen die nun vom Client zum Server geschickt werden, gehen Pakete verloren, verspäten sich, und kommen vor allem nicht in der Reihenfolge an in der sie abgeschickt wurden (Berechnugnsaufwand). Im schlechtesten Fall dauert es mehrere 100 ms bis das Paket dann tatsächlich ankommt, und bei der Anzahl an versendeten Paketen kann das durchaus öfter während einer Spielesession passieren. Wir gehen aber hier der Einfachheit halber vom "perfekten" Mittelwert aus.
Nun sind die Daten am Server. Aber was nun? Errinnert euch an die angesprochenen Ticks. Auch hier wird es wohl wieder bis zu 20 ms dauern bis der Input verarbeitet, und die daraus folgende Änderung am Zustand des Spiels berechnet und verschickt wird (wenn es nicht gar eher 2-3 Ticks dauert).
Im nächsten Schritt werden die Daten vom Server wieder an den Client gesendet. Wieder ca. 20ms. Langsam summiert sich diese kleine Zahl auf, nicht wahr?
Die Daten kommen beim Client an, und werden von diesem wieder im nächsten Tick verarbeitet, wir zählen also nochmal 20ms drauf. So, nun muss das Update auch noch als Bild beim Spieler ankommen, wieder haben wir eine kleine Verzögerung. Diese kleinen Verzögerungen fangen langsam aber auch an sich aufzusummieren, wenn ich das gerade so recht sehe.
So, das Bild ist da, der Spieler vor dir sieht nun dass bei dir eine Kugel aus dem Lauf kommt (wenn überhaupt schon). Wieviel Zeit ist nun Vergangen seit du die Maustaste geklickt hast?
80ms, ohne den ganzen "Kleinigkeiten" die ich zwischendurch unterschlagen habe, wie Datenverlust oder interne Datentransfen. Mit diesen werden es gerne mal 100+ ms, ohne dass ich die eigentliche Berechnungszeit einberechnet habe. Der oftgenannte Übeltäter "Netcode" war noch gar nicht zugange, und wir sind bereits in einem durchaus merkbaren Bereich. 100 ms reichen locker dass zbsp. solche Szenarien wie Doppel-KOs oder dass man eigentlich schon in Deckung ist noch getroffen wird, weil beim anderen Spieler noch dein Ellbogen rausguckt, Reaktionszeiten von 100ms sind bei mittleren bis besseren Spielern gar nicht so unüblich. Auf der Autobahn mit 160 km/h wäre man in der Zeit 4 Meter gefahren.
Das Problem wird nun sein, dass ihr meist eher zwischen 30 und 50 ms Pendeln werdet. Klingt jetzt auf einmal nach viel mehr, nicht wahr?
Und nun kommt der böse Netcode ins Spiel: Er muss nun möglichst alle Daten an die Clients und den Server verteilen, ohne dass der Spieler zu viel davon mitkriegt. Nur wie macht man das wenn die Übertragung an sich schon bemerkbar langsam ist? So gut wie möglich, mehr geht nunmal nicht. Wobei ich an der Stelle dazu sagen möchte, dass es durchaus sein kann dass der Netcode eines Spiels zum Himmel stinkt, das möchte ich auf keinsten Fall verneinen. Ich möchte nur nochmal dazu anregen darüber nachzudenken ob nun diese Zehntel Sekunde die ihr nicht hattet um zu reagieren, nun wirklich die Schuld irgendeines Programmierers ist, oder ob hier doch einmal einfache Hardwarebegrenzungen Schuld waren.