Unity Realtime Multiplayer, Part 6: Game Network Topologies

Written by dmitrii | Published 2023/08/28
Tech Story Tags: gaming | unity | unity-realtime-multiplayer | peer-to-peer | my.games | dmitrii-ivashchenko | network-topology | authoritative-servers

TLDRThe choice of a suitable network topology is critical for effective and stable multiplayer. We'll talk about the pros and cons of the main network topologies for real-time multiplayer: P2P, authoritative servers, relay servers, and more.via the TL;DR App

The choice of a suitable network topology is critical for effective and stable multiplayer. We'll talk about the pros and cons of the main network topologies for real-time multiplayer: P2P, authoritative servers, relay servers, and more.

Greetings again everyone, I'm Dmitrii Ivashchenko, Lead Software Engineer at MY.GAMES. Our article series on the landscape of Unity realtime multiplayer in 2023 continues — and today's topic concerns the main network topologies for realtime multiplayer.

Network Topology

The key factor in ensuring the effective and stable operation of a multiplayer game is the choice of a suitable network architecture, or topology. This decision affects both the way data is transmitted and processed in the game, as well as performance and resource consumption. Let's look at some possible models.

P2P (Peer-to-Peer)

P2P, or peer-to-peer architecture, is a model in which each player connects to every other player and exchanges data about game state and events. In “pure” P2P, there is no single "host". Instead, each client is responsible for managing its own game character (or units) while receiving updates about events from each of the other clients.

Advantages of P2P:

  • No need to develop or maintain dedicated servers.

  • Clients create direct connections with each other, providing the most direct connection (which usually, but not always, corresponds to a low ping).

Disadvantages of P2P:

  • The absence of a single authoritative host makes cheat detection significantly more difficult. This also makes compensation for delays less effective. Additionally, a "desynchronization" of clients is possible, leading to differences in game state between them.
  • Each client creates multiple outgoing connections and accepts incoming connections, so each client has to deal with firewall settings and port forwarding.

Authoritative servers

In this model, one of the nodes of the game network (this is usually initially selected or based on network connection features) becomes the "authoritative server", controlling the game state and processing all game events. The other nodes (clients) send their actions to this server and receive updated game state from it.

Server-client with the authoritative dedicated game server (DSG)

In a client-server architecture with an authoritative dedicated game server, all clients connect to a single game server. The dedicated game server (DGS) runs the game engine and is the source of the game's final state. It receives updates from connected clients, incorporates them into its game state, and sends the resulting state to each client.

MMORPGs and other games with persistent online worlds also fall into this category. In such cases, DGS also includes databases that store data about the persistent world.

Advantages of DGS:

  • The game server is "authoritative": it has the final say on whether events created by clients are valid or not. This allows for a wide range of delay compensation mechanisms and fraud prevention, as well as eliminating synchronization issues, as the server overrides the state of clients.

Disadvantages of DGS:

  • It is necessary to develop and manage a dedicated game server, and doing this has certain costs associated with it.

Leveraging a client-server architecture with an authoritative dedicated game server is one of the most common approaches in large multiplayer games and provides a high degree of control over the state of the game and combating fraud.

Server-client with authoritative client-host

In a client-server architecture with an authoritative client-host, instead of using a dedicated game server to maintain authoritative game state, it's possible to use one of the client machines as a server. This client becomes a client-host; simultaneously the host of the game session as well as a participant in the game.

Advantages of client-host:

  • Client-host has advantages as a dedicated game server but without the additional cost of running one.

Disadvantages of client-host:

  • The host machine must perform additional calculations to simultaneously perform host and client functions.
  • Locally connected clients have much lower connection latency to the host compared to other clients, which can create a competitive advantage (known as "host advantage").

The client-server architecture with an authoritative client-host allows players to independently organize multiplayer sessions without the need to connect to a dedicated game server. However, it's necessary to consider the load on the host machine and potential issues with "host advantage".

Relay server

In architecture with a relay/matchmaking server for finding opponents, the server exists to facilitate connections and data transmission between clients, but does not actively participate in the game.

Although a dedicated server is still required because it does not need to run a game engine, creation and management of this can be relatively inexpensive. Moreover, most P2P games can easily switch to using a relay server, since the network code only differs in the way clients connect to each other.

Advantages of relay servers:

  • Since an external server is used, clients only need to establish outgoing connections, so they don't need to configure port forwarding or firewalls.

Disadvantages of relay servers:

  • Relay severs have the same drawbacks as P2P, but the delay is higher because the connections are no longer direct.
  • The operation of a relay server still requires certain costs, although they are lower than those of a dedicated game server.

The relay/server architecture for finding opponents provides a simple and inexpensive solution for ensuring connections and data transmission between clients. It avoids problems related to port forwarding and firewalls, but it may have some delay due to the intermediate server.

Here's an example of the RelayServer class in C# that uses TCP to listen for incoming client connections and then add them to a list of active clients. The server then asynchronously handles each client connection by reading data and forwarding it to all connected clients:

public class RelayServer
{
    private TcpListener _listener;
    private List<TcpClient> _clients = new List<TcpClient>();

    public async Task StartAsync(int port)
    {
        _listener = new TcpListener(IPAddress.Any, port);
        _listener.Start();
        Console.WriteLine($"Server started on port {port}");

        while (true)
        {
            TcpClient client = await _listener.AcceptTcpClientAsync();
            _clients.Add(client);

            Task.Run(() => HandleClientAsync(client));
        }
    }
}

The code below represents the function HandleClientAsync, which is responsible for processing each connected client in asynchronous mode.

First, the function creates a buffer for reading data and obtains a stream for reading and writing data. Next, in an infinite loop, the function asynchronously reads data from the stream. If no data is received (i.e. the client disconnected), the function removes the client from the list and stops processing. Otherwise, the received data is converted to a string and sent to all connected clients:

private async Task HandleClientAsync(TcpClient client)
{
    byte[] buffer = new byte[1024];
    NetworkStream stream = client.GetStream();

    while (true)
    {
        int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);

        if (bytesRead == 0)
        {
            _clients.Remove(client);
            return;
        }

        string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
        BroadcastMessage(message);
    }
}

To send the received message to all connected clients, we will need the function BroadcastMessage:

private void BroadcastMessage(string message)
{
    foreach (var client in _clients)
    {
        NetworkStream stream = client.GetStream();
        byte[] buffer = Encoding.UTF8.GetBytes(message);
        stream.Write(buffer, 0, buffer.Length);
    }
}

The function takes a message as a string, iterates through the list of connected clients, and for each of them converts the message to bytes and writes it to the corresponding network connection stream. This way, the message is successfully transmitted to all clients.

Conclusion

In this article, we discussed the main network topologies for real-time multiplayer games — including P2P, authoritative server, and relay server. Each topology has its advantages and disadvantages, such as direct connections and low ping in P2P, and effective cheat detection and fraud prevention in authoritative server; relay server provides a simple and inexpensive solution for ensuring connections and data transmission between clients.

Choosing the right topology is crucial for ensuring a smooth gaming experience in real-time multiplayer games. But this decision also concerns infrastructure cost and project scalability.

In the next article, we will consider the main patterns of network architecture in different game genres.


Written by dmitrii | Crafting mobile games and robust backend systems for over a decade
Published by HackerNoon on 2023/08/28