Ich habe früher ja gerne mal die eine oder andere Runde Quake 3 Arena gespielt, auch wenn ich nie sonderlich gut war. Nachdem in der Vorlesung am Donnerstag die Frage aufkam, warum man überhaupt UDP benutzt und wie das bei Online-Spielen mit der unzuverlässigen Nachrichtenübermittlung dann überhaupt funktioniert, habe ich dann gleich mal nach Quake 3 Arena und Netzwerk gesucht, der Code ist ja schon seit geraumer Zeit frei verfügbar.

Zum Glück musste ich mich nicht durch den Quellcode selbst wühlen, das hätte wahrscheinlich sehr viel Zeit in Anspruch genommen, denn Fabien Sanglard hatte vor ungefähr drei Jahren eine Reihe von Artikeln über den Q3A-Quellcode veröffentlicht, darunter auch einen Artikel zu den Netzwerk-Funktionen.

Im Endeffekt stimmt das, was ich in der Vorlesung gesagt habe, denn gerade im Echtzeitbereich ist eine Neuübertragung von verlorenen Daten einfach keine Option: „In a fast paced environment any information that is not received on first transmission is not worth sending again because it will be too old anyway.“ Das heißt natürlich nicht, dass man nicht auf einer anderen Ebene sicherstellen muss, dass und welche Daten angekommen sind, denn sonst würde man ja unweigerlich Clients mit völlig auseinanderdriftenden Zuständen haben. Es bedeutet lediglich, dass Q3A auf UDP/IP aufsetzt, jede individuelle Nachricht auf der Transportschicht also verloren gehen kann und nicht neu übertragen wird. Die Synchronisation zwischen Client und Server wird dann von Q3A selbst übernommen.

Der oben verlinkte Artikel stellt das auch grafisch schön dar, deshalb hier nur eine kurze Zusammenfassung: im Endeffekt hält der Server den aktuellen Zustand und speichert diese Zustände auch für jeden Client individuell. Vor der Übertragung an die einzelnen Clients wird überprüft, wann der Client das letzte Mal Daten erhalten und beim Server bestätigt hat – bestätigt im Anwendungscode selbst, nicht auf der Transportschicht. Dann wird ein Delta zwischen dem letzten Zustand des Clients und dem aktuellen Zustand des Servers gebildet und nur mittlerweile geänderte Daten werden übertragen. Clever gemacht, nichts anderes hatte ich von idSoftware beziehungsweise John Carmack erwartet. :)

In einem weiteren Artikel habe ich noch einige interessante Fakten über das Netzwerkverhalten von Q3A gelesen:

  • Da einige NAT-Router die Ports des Clients zufällig neu vergeben können enthalten die Pakete eine 16 Bit lange ID, die den Client eindeutig identifiziert. Auch zwei Clients hinter dem gleichen NAT-Router können so unterschieden werden, selbst wenn sich die Ports dynamisch ändern.
  • Die verwendete MTU ist 1.400 Byte: „[John Carmack] thinks the notion of a 512-byte optimal MTU is pretty much at least 5 years out of date“ – damals vielleicht zumindest für deutsche Spieler in der Vor-Breitbandzeit noch etwas optimistisch, mittlerweile aber wohl durchaus realistisch.
  • Der Kompromiss für ein einfaches, effektives Netzwerkprotokoll erfordert dass der Server relativ große Datenmengen puffern muss, um immer ein korrektes Delta für den letzten bestätigten Zustand pro Client zu berechnen.

Einige weitere Angaben zu den Daten, die Clients an den Server schicken, habe ich noch im Artikel „Quake 3 Networking Primer“ gefunden. Ansonsten hatte ich glaube ich in einem der Artikel auch etwas zur Datenrate gelesen, das habe ich aber nicht mehr gefunden. Im wesentlichen sieht man, dass man mit den beiden Standard-Anwendungsfällen (Anwendungsfälle, dazu könnte mir Hubert sicher einiges mitteilen) „zuverlässig, verbindungsorientiert“ und „unzuverlässig, verbindungslos“ nicht beliebig viele Fälle abdeckt. Wenn beides in der Standardvariante nicht ausreicht, muss man eben auf einer höheren Schicht die gewünschte Funktionalität implementieren.