Game loops in MMORPGs

How does your game loop look like?
How does your game loop look like?

A game loop is the central component of any game. There are a number of special challenges these loops face in MMORPGs. Discover, how to make it work. Warning: difficult topic!

Table of Contents


Simple game loops

What is a game loop?

A game loop is the central component of any game. It allows the game to run, regardless of player input. In almost every computer game, no matter its complexity, there is a loop similar to this:

while (!QuitRequested())
{
    GameLoop();
}

Game loop in a boardgame

Imagine a game for two players. On the gameboard, there is a white figure and a blue figure. Each player controls one figure. The players can move the figures and cast spells at each other.

White Player
Blue Player

The game loop in this game:

  • White turn
  • Blue turn

A game loop of this kind is found in many classical games, for instance in chess.

Game loop in a computer game

Imagine the same game. This time the blue figure is controlled by a computer. The game loop in this game:

  • Player turn
    • collect player input
    • process player action
  • Computer turn
    • calculate creature action
    • process creature action

In most games, there is more than one enemy. This game loop also works with multiple creatures. The loop iterates through all creatures to calculate and process their actions.

Splitting game state from its depiction

When going from board game to computer game we replace the game materials. Instead of a board and figures, we have a game state and a depiction of that state.

Note, that the game loop modifies the game state in each “process” step. It is important to understand, that the update of the game state and the update of the depiction of that state are two different things.

The depiction is calculated for every frame. You can measure the frequency of the depiction of a game state in frames per second. This value varies from client to client.

The game loop doesn´t need to iterate every frame. Similarly to the framerate, you can measure the frequency of the iteration of the game in ticks per second.

Many single-player games have connected framerate and ticks for convenience. However, this is not possible in an MMORPG.

Turn-based and real-time

Games that wait until the player has made an input are turn-based games.

Games that iterate the game loop independent of player input are real-time games. However, under the hood even the real-time games are turn-based. Each turn is given a certain time interval. Players doing nothing in their time interval are considered to have passed.


The client game loop in an MMORPG

In MMORPGs, the player input comes from multiple clients, and the creature actions are generated on the server. Both clients and the server, hold the game state. The clients read from the game state to generate a depiction of it for the player. The server writes the game state. Both need to communicate with each other.

Simple client game loop

The game loop on the clients:

  • collect player input
  • send player input to the server
  • receive game state from the server

The client must establish the illusion of smooth gameplay. Therefore, it must solve two problems:

Firstly, the game loop iterates much slower than the frame updates on the client. Therefore, the clients have to interpolate the depiction of the game state.

Secondly, the player’s input comes much faster than the game loop ticks. The client has to implement a strategy to hide this. Therefore, we need to modify the client game loop.

Warning: From here on the difficulty reaches toxic levels. Don´t let that scare you away. Rest assured that server architecture is one of the most difficult topics in MMORPG creation.

How to run a smooth client

Well, we might create a smooth game state interpolation on the client, and the server runs nicely. However, we still don´t know how to handle the player input right.

When you follow the three golden rules of multiplayer safety, there are two approaches to handle player processing.

Send inputs to the server

The first approach is to send all inputs to the server. The server processes each detail of the new game state and sends it back to the client.

This approach is used by fast-paced games with a limited number of players and by streamed games.

The advantage is, that you have a stronger grip on the client and cheating may be harder. However, the client can still cheat by optimizing player input (aimbots) and by modifying the depiction of the game state (transparent walls, highlighted enemies).

Warning: From here on the difficulty reaches toxic levels.

If you have any problems understanding, ask now!

The disadvantage is that you need rock-solid connections to each client and a server that is able to calculate all details for a high number of clients in a short amount of time.

I strongly advise against this approach for an MMORPG. Players are very sensitive to delays in input processing. They already feel delays as small as 10 to 50 milliseconds.

Send predicted states to the server

The second approach is to instantly process the player input and predict the results. In fixed intervals, the client sends the predicted results to the server for validation. In case of a wrong prediction, the server corrects the client.

The advantage is that player input results in immediate player action. This results in a very smooth gameplay experience. The game loop connects framerate and loop ticks.

This disadvantage is, that you have to predict game states on the client and you have to correct these states from time to time. Players experience this as the rubber-band effect.

Optimized client game loop

In the end, we have a linear game loop on the client that is supported by a separate thread that receives the game state from the server. The threads work together via the concurrent queue received-queue.

The optimized game loop on the client:

Receive thread

This thread processing is natively parallel.

Receive game states from the server and put them in the received-queue.

Client game loop thread

This thread processing is linear and one loop iteration matches one frame.

  • collect player input
  • predict game state as far as possible:
    • send game state change requests to the server instantly (e.g. spell cast requests)
    • send certain game state updates with a fixed frequency (e.g. position)
  • depict interpolation of the game state
  • for each entry in the received-queue: modify or correct the game state

You are looking at the core of an MMORPG client game loop. Take your time to understand everything.

You have done half of the article. It´s a good time to take a short break here. The following chapter on the server game loop is not for the faint of heart.


The server game loop in an MMORPG

Simple server game loop

A simple game loop on the server might look like this:

  • for each client:
    • receive predicted game state of the client
    • validate predicted game state
    • reject the predicted game state when invalid
  • for each creature:
    • calculate creature action
    • process creature action
  • for each client:
    • send game state

You may notice, that the server game loop is pretty extensive. On top of that, when designing an MMORPG you have to consider the worst case. Consider how long the loop takes with the maximum number of clients and creatures in one place that your game allows.

Everything depends on your hardware and your game settings. However, giving you some numbers from experience, that loop may take 50 to 200 milliseconds.

The goal of server architecture strategies and server optimization is to tame this game loop.

Game state consistency

Reading the game state is a simple procedure. However, every change to the game state is a delicate undertaking. Why is that so?

A simple metaphor: imagine the game state to be like your phone number. Giving your number to others is a simple task. You can even give your number to a group of persons by shouting it out. However, when you need to change your number, you must take care to tell a lot of persons the new number.

There may be an inconsistency between the client game state and the server game state. That is easy to resolve when you follow the three golden rules of MMO safety. The server is always right.

However, there must never be an inconsistency in the server game state. Therefore, every modification to the game state has to happen in a bullet-proof manner.

The simplest way is to keep the game state on a single server. The only disadvantage of this architecture is its performance limitation. There are strategies to distribute the game state on several servers to increase performance. This topic is described here.

Also, there are tricks to handle large amounts of players. These strategies are described here.

Processing game state

Processing the game state usually involves accessing the properties of players, creatures, and other entities of the game world. Each entity shares nothing with the other. However, processing the status of one entity can affect the status of another entity.

Parallel reading of old game state, processing and writing of new game state.

Processing entities in parallel would contribute greatly to the scaleability of the server game loop. Reading from the old game state is possible in a parallel way.

However, writing the new game state will fail or yield wrong and unpredictable results when different entities try to alter the same value.

Parallel reading and processing of old game state, sequential writing of new game state.

Therefore, you need to queue the writing operations to the new game state. Read more about parallel programming basics here.

Also, you need to make these writing operations so that their order of operation doesn´t alter the result. The simplest way to achieve this is to alter values only via additions (you can also add negative values).

Receive predicted client state

Clients may send their state all the time. However, that doesn´t mean the server has to process this instantly. Furthermore, the server catches the messages by separate threads. How this works is described here. The server stores the messages in a received-queue. By doing so, they become accessible in a linear way.

At a certain point in the game loop, it is time to dequeue the messages. So how to do it, when there is a constant influx of new messages to the queue?

You can do this by switching queues which is a common way.

Alternatively, in C# you can use the ConcurrentQueue class that allows concurrent access to a queue. That class saves us a lot of headaches.

However, when you dequeue this way, you may run in an infinite loop as the queue is constantly refilled with new messages.

ConcurrentQueue<Message> receivedQueue;

while (receivedQueue.TryDequeue(out Message result))
{
    //Process result   
}

Therefore, sample the size of the queue at the beginning, and dequeue only as many elements.

ConcurrentQueue<Message> receivedQueue;

int entryCount = receivedQueue.Count;
for (int i = 0; i < entryCount; i++)
{
    receivedQueue.TryDequeue(out Message result);
    //Process result   
}

Almost perfect. Be paranoid in multithreading and don´t ignore the return value of a method.

ConcurrentQueue<Message> receivedQueue;

int entryCount = receivedQueue.Count;
for (int i = 0; i < entryCount; i++)
{
    if (!receivedQueue.TryDequeue(out Message result))
        break;
    //Process result   
}

Send game state

Send the right state

Any modification that happens to the game state needs to be communicated to the clients. Not to all clients, just to the clients in range (Field-of-View strategy).

So, whenever your server modifies a game state, it must create a message that describes the new state. Don´t bother with actually sending that stuff in your game loop. Just put it in a sending-queue.

It is the task of the send thread to dequeue the sending-queue and send all states to the clients that need to know. Pay attention: the server must not send the current game state. Rather, it sends the state that was stored in the message at the time of their creation.

This is important, to prevent inconsistencies. So don´t use a direct reference to the game state in these messages.

Sending parallel

The server may send the messages in a parallel manner because sending one message does not affect the other messages. In the end, the capabilities of the server network hardware will determine whether parallel sending gives you an advantage.

However, consider that small messages that were later in the queue may arrive earlier at your client than large messages that were earlier in the queue. This doesn´t need to be a problem, yet you should keep it in mind.

Optimized server game loop

In the end, we have a linear game loop on the server that is supported by two separate threads that send game data and receive client data. The threads work together via the two concurrent queues received-queue and sending-queue.

The optimized game loop on the server:

Receive thread

This thread processing is natively parallel.

Receive predicted game states from clients and put them in the received-queue.

Send thread

This thread processing can be parallel.

Dequeue the sending queue. Send the new state of the entity to the clients. That state that is sent may differ from that currently on the server.

Use Field-of-View strategy, which means game state changes of an entity are only sent to clients that are in range to it.

Server game loop thread

This thread processing is linear.

  • for each entry in the received-queue (= all clients):
    • reject or process the predicted game state
    • put the player state in the sending-queue
  • for each creature:
    • calculate creature action
    • process creature action
    • put creature state in the sending-queue
  • for any other change of the game world
    • process change
    • put new world state in the sending-queue

Don´t feel overwhelmed. You are looking at the core of an MMORPG server game loop. Take your time to understand everything. Feel free to ask in the comments.


Checklist

The server game loop consists of at least three threads that run in parallel:

  • receive thread
  • send thread
  • main loop

In the main loop the next game state is created from the inputs and the present state. This process is called a server tick. It involves parallel reading the old state and processing the next state. However, writing the next state needs to happen sequentally, to prevent data inconsistency.

Read further on parallel programming basics, scalable server architecture, and handling large amounts of players.


Server Sid
Server Sid

Game loops in MMORPGs should process the game state parallel, yet write it sequentally. They have supporting threads for network communications.

(Last Updated on April 12, 2021)

Leave a comment

Your email address will not be published.