Questions on Rollback/Lockstep

I’m checking out this github project for this that was posted by you guys on the discord: https:// github .com/coherence/gamejam-wordsand (Links not allowed)

I’m trying to make sure I understand this properly.

  1. Coherence input queues are the standard workflow.

  2. Because this project is deterministic by nature, misprediction and rollback is handled automatically.

  3. All thats necessary in this case is to set simulation to Client side

  4. In server-side auth, simulation must be called on client manually, and misprediction must be detected by comparing frame values manually too. (Presumably every other frame)

  5. In both workflows a SimulationState struct must be defined. But rollback is not called in server-side auth sims for obvious reasons. So I must call them manually using the OnNetworkReceived callback.

  6. Input buffer works in both modes. Allowing you to set input delay to manage mispredictions better.

I’m also curious about one other aspect. GGPO has whats called “Frame Advantage.” This is where clients may slowly drift out of time sync with one another. Usually in this case, the client who is ahead will pause in lockstep to allow the other player to catch up. What does coherence do in this case? Also does coherence allow us to set how many frames to simulate? Example, a player who has very high latency might have to simulate more frames than another player, in BOTH client-side or server-side auth workflows correct?

Thank you so much in advance for the help. I’m actually really liking how simple everything seems on the surface!

1 Like

Hey there @BlankMauser!

I’m glad that you like coherence. Making it simple yet powerful is one of our top goals. I can’t wait to see what you can build with it :slight_smile:

Let me try to address your points:

  1. Coherence input queues are the standard workflow.

It is one possible workflow, yes.

  1. Because this project is deterministic by nature, misprediction and rollback is handled automatically.

Not yet, but we do help with rollback via CoherenceInputSimulation<SimulationState> (more on this in the docs). We are planning to make it automatic though.

  1. All thats necessary in this case is to set simulation to Client side
  2. In server-side auth, simulation must be called on client manually, and misprediction must be detected by comparing frame values manually too. (Presumably every other frame)
  3. In both workflows a SimulationState struct must be defined. But rollback is not called in server-side auth sims for obvious reasons. So I must call them manually using the OnNetworkReceived callback.
  4. Input buffer works in both modes. Allowing you to set input delay to manage mispredictions better.

CoherenceInputSimulation<T> was built specifically for GGPO type of games and so it doesn’t play well with the server-side auth. It expects inputs from all clients to be delivered whereas in server-side auth mode input is delivered only to the Simulator (aka game server) that is producing and syncing the game state. As of today, we do not have any utilities for reconciliation in server-side auth mode, but full FPS support (prediction, reconciliation, lag compensation) is on our roadmap so stay tuned!

I’m also curious about one other aspect. GGPO has whats called “Frame Advantage.” This is where clients may slowly drift out of time sync with one another. Usually in this case, the client who is ahead will pause in lockstep to allow the other player to catch up. What does coherence do in this case?

All clients sync their frames with the replication server. Each client then uses Time.timeScale to speed up or slow down the simulation to make the local frame match the server frame. If instead, you’d prefer to pause the simulation to let other players catch up, then you can disable the timeScale control in the CoherenceMonoBridge settings and pause the simulation manually.

Also does coherence allow us to set how many frames to simulate? Example, a player who has very high latency might have to simulate more frames than another player, in BOTH client-side or server-side auth workflows correct?

The number of frames that can be predicted is controlled directly via input buffer size (configurable via CoherenceInput inspector). A buffer with a size of 5 allows for predicting 5 frames into the future. If we don’t get inputs from all clients within those 5 frames then a pause will be issued.

When it comes to players with high ping I don’t think there’s a single best solution. We can:

  • Set big input delay for a high-ping player - this will make the game tough for the high-ping player (inputs will feel laggy) but smooth for low-ping player
  • Introduce simulation frame delay for the high-ping player - high-ping player will get constant rollbacks
  • Keep static input delay and simulation frames in sync - low-ping player will get constant rollbacks due to late inputs from the opponent. Smooth experience for the high-ping player

I hope this helps answer your questions and gives you a better understanding of how inputs work in coherence. If you have any further questions or run into any issues while using coherence, don’t hesitate to reach out!

1 Like

Thanks for the response! Maybe if I describe my goals you might be able to provide some direction for me.

I’m actually trying to find where the “Rollback” function is called in the example embarrassingly enough. If I can have full control over it, it may still suit my needs.

I realize CoherenceInputSimulation was built for GGPO type games, and Photon Fusion had a similar issue with its server-auth mode. So what I did was set every player’s input to be “Synced” through networked variables. (Cheap synced bit flags basically)

This let the simulation continue using the “predicted” input. And surprisingly there were very few problems with this workflow.

However, in photon fusion there is very little you can do on the simulation side. Things like adding input delay is not supported, and custom server logic often seems to require paying for plugins.

I’m wondering if I can do the same here, but have more control over the timekeeping and input delay to reduce rollbacks. As well as induce rollbacks and have access directly to the states being sent. One thing about fusion that was convenient was being able to add [Networked] to any variable so I didn’t need to keep them all in one struct like here.

You say input buffer size is for prediction, then which setting in CoherenceInput can specifically set a delay? Or is that something I should implement manually as well?

Cheers.

I’m actually trying to find where the “Rollback” function is called in the example embarrassingly enough. If I can have full control over it, it may still suit my needs.

There’s a virtual CoherenceInputSimulation.Rollback(long toFrame, SimulationState state) function. It is called automatically whenever we detect a misprediction in a given frame.

I realize CoherenceInputSimulation was built for GGPO type games, and Photon Fusion had a similar issue with its server-auth mode. So what I did was set every player’s input to be “Synced” through networked variables. (Cheap synced bit flags basically)

One thing to keep in mind is that CoherenceInputSimulation relies on a deterministic simulation while Fusion is a state-sync solution. To achieve a setup similar to the one in Fusion it’s probably best to use CoherenceInput with prediction and skip the CoherenceInputSimulation entirely.

I’m wondering if I can do the same here, but have more control over the timekeeping and input delay to reduce rollbacks. As well as induce rollbacks and have access directly to the states being sent.

Yes, you can! We do not support automatic rollbacks (yet!) but the docs contain an example of manually handling a misprediction by inspecting the received state.

One thing about fusion that was convenient was being able to add [Networked] to any variable so I didn’t need to keep them all in one struct like here.

I’m not sure if that’s what you’re looking for but we do have a [Sync] attribute:

[Sync] public string Name;
[Sync] public int Health;

which results in those variables being marked for syncing:

obraz

You say input buffer size is for prediction, then which setting in CoherenceInput can specifically set a delay? Or is that something I should implement manually as well?

Input delay can be set either via CoherenceInput inspector:

obraz

or in code:

var coherenceInput = GetComponent<CoherenceInput>();
coherenceInput.Delay = 3;

All that said I’m still uncertain what type of game we’re talking about. If you could give me some hints it would probably help me guide you in the right direction:

  • What is the game genre?
  • Does it use an authoritative server?
  • Is the game deterministic?
  • Is Unity physics used?

It is not deterministic currently but only a few steps removed from it. It’s a very tight action game, but not so tight that a little input delay would ruin it.

The only unity physics used are physics.raycast and colliders. The gist of it is, to hopefully gain the advantages of ggpo, while not sacrificing the simple state transfer versatility. State AND input are synced, and re-simulated when you rollback. Normally other players are remote proxies in this case but not here.

1 Like

I see. In that case, I’d go with CoherenceInput, prediction, and custom rollback code based on state mismatch (no CoherenceInputSimulation).

As noted before, we do plan to bring a whole suite of tools for games just like this (including automatic reconciliation), but I can’t promise any dates at this moment.

On a final note, we’re eager to hear your feedback on the current workflow. We’re also excited to see what’s being cooked with coherence, so do not hesitate to share your project if you get something rolling!

1 Like