3
\$\begingroup\$

I am developing a fast-paced multiplayer shooting game and following instructions from this source http://www.gabrielgambetta.com/entity-interpolation.html. In the article it says that:

several clients may be sending inputs simultaneously, and at a fast pace (as fast as the player can issue commands, be it pressing arrow keys, moving the mouse or clicking the screen). Updating the game world every time inputs are received from each client and then broadcasting the game state would consume too much CPU and bandwidth.

A better approach is to queue the client inputs as they are received, without any processing. Instead, the game world is updated periodically at low frequency, for example 10 times per second. The delay between every update, 100ms in this case, is called thetime step. In every update loop iteration, all the unprocessed client input is applied (possibly in smaller time increments than the time step, to make physics more predictable), and the new game state is broadcast to the clients.

now I am wondering how to implement such a queue system? I can have an in memory queue where each input is added. and after say 100ms how many number of inputs do I process? i.e when should I stop popping events from queue and apply simulation?

from my point of view clients are sending inputs constantly which are being added to the input queue. below is the psuedocode.

queue inputQueue;

gameloop() {
   while (inputQueue not empty) { //<------obviously i cannot use this condition, what should i use then?
      inputEvent = inputQueue.front()
      updateState(inputEvent)
   }
}
\$\endgroup\$
  • \$\begingroup\$ The text you quoted specifically says all of them. \$\endgroup\$ – user253751 Jun 20 at 23:04
1
\$\begingroup\$

You could combined the "is the queue not empty" check with a current time check.

Essentially just process the queue one item at a time, up to a time limit. Then anything that is still in the queue will get processed on the next step.

queue inputQueue;

// This should be low enough that you process enough items per 
// slowing down your overall simulation, but high enough that
// step without your simulation doesn't lag too much. Tuning 
// this is dependent on your application.
const uint TIME_LIMIT = 5; 

gameloop() {
   uint processUntilTime=now() + TIME_LIMIT; //process the queue for up to _TIME_LIMIT ms from now

   while (inputQueue not empty && now() <= processUntilTime) { 
      inputEvent = inputQueue.front()
      updateState(inputEvent)
   }
   // Either inputQueue is empty or TIME_LIMIT has been reached
}
\$\endgroup\$
1
\$\begingroup\$

The purpose of the server's time-keeping is to enforce a common view of the order in which events occur, so all players can (eventually) agree on "who shot first" and other time/sequence-related gameplay distinctions.

So, when a client sends you an action, your server assigns it a timestamp that it will consider to be its "effective time of action". This could be the time of receipt, or a back-dated time to try to compensate for the estimated network latency.

Each server update also has an effective timestamp, "This is the up-to-date state of the match as of XX:XX." You can compute this timestamp by adding exactly one fixed update interval to the timestamp of the previous server update.

During the server update pass, process all items in your priority queue whose effective time of action is before the effective time of this update. Any later actions happened "after" the current update pass, and can stay in the queue until the next update step.

If you do compensate for latency, this can mean a client message sent after an update has been processed can be assigned an effective time of action that should have been processed in that past update. Servers that operate this way will rewind the logical game state to this moment, to apply the action at the appropriate effective moment, then re-simulate back up to the current timestep and send corrections as needed, to keep the final view of the sequence of actions consistent for all players. This is more complex than working off of time of receipt, but can improve perceived fairness in the presence of latency.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.