Skip to content

Multiplayer

Valk edited this page Feb 2, 2026 · 70 revisions

All multiplayer wiki pages including this one are WIP.

Multiplayer.Preview.mp4

Important

If you are running Mac or Linux you may need a Custom ENet Build

Note

Each packet comes with a small overhead, either 1 or 2 bytes, depending on configured reliability and a one-byte opcode to identify its purpose. Everything else in the packet is strictly the data we send.

Packets

First familiarize yourself with how to create your own packets.

GameClient

Create a GameClient script with something like this.

public partial class GameClient : GodotClient
{
    public GameClient()
    {
        // We register the server packet SPacketHello so we do something when it is received by the client.
        // In this example we just log the packets message, but you can really do anything you want.
        RegisterPacketHandler<SPacketHello>(packet => Log(packet.Message));
    }

    protected override void OnConnect(Event netEvent)
    {
        // Send the client packet CPacketPlayerInfo from the client to the server.
        Send(new CPacketPlayerInfo()
        {
            Username = "Valk",
            Position = new Vector2(100, 100)
        });
    }
}

GameServer

Create a GameServer script with something like this.

public partial class GameServer : GodotServer
{
    // Player is just a simple class with properties like Username and Positions
    public Dictionary<uint, Player> Players { get; } = [];

    // PlayerSystems is too big to show here but all it is doing is populating the Players 
    // dictionary when packet data is received.
    private PlayerSystems _playerSystems;

    public GameServer()
    {
        _playerSystems = new PlayerSystems(this);

        // We register the client packet CPacketPlayerInfo so we do something when it is received by the server.
        // Add the player to Players
        RegisterPacketHandler<CPacketPlayerInfo>(_playerSystems.OnPlayerInfo);
    }

    protected override void OnPeerDisconnect(Event netEvent)
    {
        // Remove netEvent.Peer.ID from Players dictionary
        _playerSystems.OnPlayerDisconnect(netEvent);
    }
}

PlayerSystems is just managing what gets added or removed from Players and your code may look very different from this so don't worry too much about how this looks.

PlayerSystems.cs
public class PlayerSystems
{
    private readonly GameServer _server;

    public PlayerSystems(GameServer server)
    {
        _server = server;
    }

    public void OnPlayerInfo(CPacketPlayerInfo info, Peer peer)
    {
        if (_server.Players.ContainsKey(peer.ID))
        {
            _server.Log($"Received player info for peer {peer.ID} (username {info.Username}) but they exist on the server already");
            return;
        }

        _server.Players[peer.ID] = new Player
        {
            Username = info.Username,
            Position = info.Position
        };

        _server.Send(new SPacketHello { Message = "What's up?" }, peer);
    }

    public void OnPlayerDisconnect(Event netEvent)
    {
        uint id = netEvent.Peer.ID;

        if (!_server.Players.ContainsKey(id))
        {
            _server.Log($"Can't remove peer {id} from players because they never existed to begin with");
            return;
        }

        _server.Players.Remove(id);
        _server.Log($"Removed peer {id} from players");
    }
}

NetControlPanel

This is the UI interface and how you will be able to start the server and client.

Create a script that extends from NetControlPanelLow<GameClient, GameServer>. Attach this script to a UI node in your scene and supply all the exposed export nodes. For example you need a LineEdit for the IP and a Button to start the server.

public partial class NetControlPanel : NetControlPanelLow<GameClient, GameServer>
{
    protected override ENetOptions Options { get; set; } = new()
    {
        PrintPacketByteSize = true,
        PrintPacketData = true,
        PrintPacketReceived = true,
        PrintPacketSent = true
    };
}
image

Enabling the print packet options can be very useful.

image

You now have everything you need to develop your multiplayer.

Also see common mistakes.

Example netcode has been provided in res://Framework/GodotUtils/Netcode/Sandbox/TopDown/World.tscn

Clone this wiki locally