Jump to content
  • Advertisement

Overwatch - Client Input Buffer + Dynamic FixedTimeStep

Recommended Posts

Posted (edited)

I have my netcode set up that my Server receives client inputs, and stores them in a buffer.

As seen in the Overwatch GDC talk, it is described how the client will 'speed up' and 'slow down' it's FixedTimeStep as to send more or less input frames to the Server as needed to compensate for latency and keep the Server on the "bleeding edge" of client inputs. (Meaning that we want our client input buffer to have as few inputs waiting in the buffer as possible, but never empty)

I've been struggling for a few weeks now trying to write some semi intelligent code that could help me achieve this in my game. I'm at a loss at this point and am hoping more sets of eyes can help me understand what I might be doing wrong. Below you will see the method 'ClientReceiveBufferState' which is called over the network from Server to Client, passing the last frame # the Server received from the client, and it's current server time TimeStamp. The 'timeChangedFrameCount' variable is incremented by 1 each FixedTimeStep. (I'm using Unity)

I'm attempting to keep my Server's client input buffer filled with 2 or 3 inputs waiting at any given time.

My thought was that I could more or less calculate the number of frames that the client has become behind or ahead of the Server and Speed Up / Slow Down my fixedTimeStep for that many frames.... but this is not working. Currently when I test with a higher latency, my client gets permanently stuck behind the Server's tick # and it's Frame # is always irrelevant (outdated) once it reaches the Server. Am I over complicating this?

void ClientReceiveBufferState(uint lastQueuedFrame, long serverTimeStamp)
  // Determine how far behind the server we are
  long serverTime = TNManager.serverTime;
  int mTick = (int)SimulationManager.MasterTick;
  int overTheWireTickCount = (int)(((Mathf.Abs((serverTimeStamp - serverTime))) * 0.001f) / 0.0167f); // Convert to milliseconds and divide by 'normal' FixedTimeStep
  uint serverClientTickDiff = (uint)Mathf.Abs(((int)lastQueuedFrame + overTheWireTickCount) - mTick);

  if (timeChangeActive)
    // Check if we're back in a good state
    if (timeChangedFrameCount >= desiredChangedFrameNumber)
      Time.fixedDeltaTime = 0.0167f; // 'normal' 60 ticks per second
      bufferStatus = InputBufferStatus.Normal;

      timeChangeActive = false;

  if (!timeChangeActive) {

    if (serverClientTickDiff <= 1) // Going to run out of client inputs in buffer, speed up!
      if (bufferStatus != InputBufferStatus.Empty) {
        bufferStatus = InputBufferStatus.Empty;
        timeChangeActive = true;
        timeChangedFrameCount = 0;
        desiredChangedFrameNumber = (int)(((Mathf.Abs((serverTimeStamp - serverTime))) * 0.001f) / 0.0157f);

        // Speed Up
        Time.fixedDeltaTime = 0.0157f; // 'faster' 63 ticks per second
    else if (serverClientTickDiff > 3) // Too many client inputs waiting in buffer, slow down
      if (bufferStatus != InputBufferStatus.Full) {
        bufferStatus = InputBufferStatus.Full;
        timeChangeActive = true;
        timeChangedFrameCount = 0;
        desiredChangedFrameNumber = (int)(((Mathf.Abs((serverTimeStamp - serverTime))) * 0.001f) / 0.0177f);

        // Slow Down
        Time.fixedDeltaTime = 0.0177f;// 'slower' 56 ticks per second

Thanks for your time.

Edited by RxMarcus

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!