Verzögerungen in Online-Spielen durch Client-Side Prediction kompensieren

Seite 4: Korrekturmöglichkeiten

Inhaltsverzeichnis

Nicht ohne Hintergedanken wurden bei der Einführung der Client-Side Prediction die gesendeten Eingabedaten auf dem Client gespeichert. Mit ihrer Hilfe lassen sich die eingegangenen Zustandsdaten auf denselben Zeitpunkt überführen, auf dem sich die Spielfigur befindet. Dazu sind alle Eingabedaten, die seit dem Absenden der Clienteingaben eingegangen sind, auf die Zustandsdaten anzuwenden, bevor man sie der Figur des Spielers zuweist:

private void OnStateReceived(WorldState state)
{
// Get own state.
ClientState clientState = state.GetClientState(this.ClientId);
if (clientState == null)
{
return;
}

// Remove inputs which arrived at server.
while (this.sentInputs.Count > 0 && this.sentInputs.Peek()
.InputNumber <= clientState.InputNumber)
{
this.sentInputs.Dequeue();
}

MoveState newMoveState = clientState.MoveState;

if (this.Reconciliation)
{
// Re-apply unacknowledged inputs.
foreach (var clientInput in this.sentInputs)
{
newMoveState = this.physics.TickSimulation(
newMoveState, clientInput.Input,
this.PhysicsUpdateInterval);
}
}

// Set new move state.
this.MoveState = newMoveState;
}

Auf die Weise lassen sich die Serverzustandsdaten berücksichtigen, die ja auf jeden Fall korrekt sind, und der Spieler kann gleichzeitig seine Spielfigur unmittelbar steuern.

Die sog. Reconciliation aktualisiert den Serverzustand bevor dieser zugewiesen wird. (Abb. 4)

(Bild: Gabriel Gambetta, http://www.gabrielgambetta.com)

Tim Sweeney, verantwortlich für die Integration der Client-Side Prediction in Unreals Networking Model, beschreibt den Ansatz wie folgt:

"This approach is purely predictive, and it gives one the best of both worlds: In all cases, the server remains completely authoritative. Nearly all the time, the client movement simulation exactly mirrors the client movement carried out by the server, so the client's position is seldom corrected. Only in the rare case, such as a player getting hit by a rocket, or bumping into an enemy, will the client's location need to be corrected."

Eine der Voraussetzungen der Client-Side Prediction war: "Die Bewegung wird ausschließlich von den Eingabedaten des Spielers gesteuert." Daher sind, wie auch Sweeney erwähnt, Korrekturen unvermeidbar, wenn die Spielfigur durch äußere Einwirkungen beeinflusst wird -- etwa durch eine Explosion, die sie trifft. Ein weiterer Grund kann sein, dass Eingabedaten nicht oder mit veränderter Verzögerung angekommen sind (z.B. durch einen temporären Peak). In dem Fall wurde die Eingabe auf dem Client zu einem anderen Zeitpunkt in die Bewegungssimulation einbezogen als auf dem Server, wodurch eine veränderte Bewegung zustande kommt.

Angenommen, die Figur bewegt sich momentan nach links und der Spieler wechselt die Richtung. Die Eingabedaten erreichen den Server nicht wie bislang nach 100 ms, was zwei Updates der Simulation entspricht, sondern ausnahmsweise erst nach 150 ms, also drei Updates. Da der Server die Autorität über den Weltzustand hat, wurde die Eingabe auf dem Client des Spielers somit ein Update zu früh einbezogen. Dies fällt allerdings auf dem Client 250 ms zu spät auf, nämlich erst, wenn das Zustands-Update vom Server eintrifft. Es sollte laut der Vorhersage die Eingabedaten enthalten, allerdings arbeitet es tatsächlich noch mit den vorherigen Eingabedaten.

Ohne gesonderte Behandlung würde die Figur nun abrupt auf die vom Server vorgegebene Position springen, was der Spieler in den meisten Fällen bemerkt. Eine einfache Behandlung wäre, den Bewegungszustand lediglich teilweise zu korrigieren, sodass die Nachbesserung weniger offensichtlich geschieht. In späteren Updates ist häufig eine erneute Korrektur nötig, aber solange Fehler nicht allzu oft auftreten, sollte der Zustand innerhalb einiger Updates wieder synchronisiert sein.

Da die gesamte Bewegungssimulation auf dem Client zur Verfügung steht, bietet sich allerdings noch eine weitaus subtilere Korrekturmöglichkeit an. Die Idee ist, sowohl die Bewegungssimulation auf dem Client inklusive des Fehlers weiterzuberechnen, als auch die korrekte Variante, die auf den Daten des Servers beruht. Die Korrektur findet nun anhand von linearer Interpolation über mehrere Updates zwischen den beiden berechneten Zuständen statt.

Die Methode ähnelt stark der direkten Korrektur bei der nur eine teilweise Korrektur vorgenommen wird. Allerdings hat sie den Vorteil, dass hierbei nicht nach jedem Update der Weltzustand zu den Clients zu schicken ist. Es würde stattdessen genügen, nur ein Zustands-Update zu schicken, wenn sich die Eingabedaten geändert haben. Auf der anderen Seite sind dem Server auch modifizierte Eingabedaten zu senden. Solange keine neuen Daten den Server erreichen, nutzt er die vorhandenen für die weitere Simulation. Die Implementierungsdetails dieser Optimierungen sowie der Korrektur durch lineare Interpolation würden allerdings den Rahmen dieses Artikels und des Beispielprogramms sprengen.