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

Seite 3: Vorhersagemechanismen

Inhaltsverzeichnis

Der Client wiederum wartet auf die Zustands-Updates vom Server, um seinen Bewegungszustand zu aktualisieren:

public class Client
{

...

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

MoveState newMoveState = clientState.MoveState;

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

...

}

Soweit, so standardmäßig. Wie bereits erwähnt, verhindert diese Architektur, dass ein Spieler sich durch eine Manipulation des Clients einen unfairen Vorteil verschaffen kann, da die gesamte Spiellogik auf dem Server stattfindet.

Setzte man den Client in solch einem Zustand ein, würden im lokalen Netzwerk kaum Probleme auftreten. Kritisch wird es erst, wenn Spieler übers Internet gegeneinander antreten oder man ein künstliches Lag erzeugt, wie es im Beispielprogramm möglich ist. Dann fällt sofort auf, dass sich die Spielfigur nach einer Eingabe erst verzögert in Bewegung setzt.

An der Stelle kommt nun der erste Teil der Client-Side Prediction ins Spiel. Statt nur die Eingaben zum Server zu senden, wendet der Client sie ebenfalls sofort lokal auf seinen Bewegungszustand an. Zusätzlich speichert er die gesendeten Eingabedaten, da sie später für einen Abgleich nötig sind:

private void FixedUpdate(float updateInterval)
{
...

if (this.Prediction)
{
// Apply input to state.
this.MoveState = this.physics.TickSimulation(this.MoveState,
input, updateInterval);
this.sentInputs.Enqueue(clientInput);
}
}

Durch diesen simplen Trick bewegt sich die Figur im Spiel, sobald das Programm die Eingabe erfasst hat. Es ergibt sich allerdings ein neues Problem: Sie bewegt sich zwar sofort, fängt allerdings kurz danach an zu "ruckeln". Das ist den Korrekturen durch den Server geschuldet, die den lokalen Zustand überschreiben, sobald ein Zustands-Update den Client erreicht. Um das zu umgehen, wird der zweite Teil der Client-Side Prediction, die sogenannte Reconciliation, benötigt.

Trotz der Änderungen handelt es sich bei der Architektur immer noch um einen autoritativen Server. Daher sind die Zustandsdaten, die der Client vom Server empfängt, zu nutzen, um die Figuren auf die richtigen Positionen zu bewegen. Momentan erledigt das die Methode OnStateReceived. Weil das Programm die Eingabedaten bereits bevor sie zum Server gesendet wurden zum Bewegen der Spielfigur genutzt hat, befindet sich letztere danach sozusagen in der Zukunft. In dem Moment, in dem die Eingabedaten auf dem Server eintreffen beziehungsweise die aktualisierten Zustandsdaten den Client erreichen, hat die Spielfigur womöglich schon weitere Eingaben verarbeitet. Im jetzigen Zustand überschreiben die vom Server empfangenen Zustandsdaten einfach die auf dem Client, was zu dem beobachteten Ruckeln oder Zurücksetzen der Figur führt.

Synchronisationsprobleme bei mehreren zeitnahen Eingaben (Abb. 3)

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