-
Notifications
You must be signed in to change notification settings - Fork 13
Multiplayer
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.
First familiarize yourself with how to create your own packets.
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)
});
}
}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");
}
}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
};
}
Enabling the print packet options can be very useful.
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
Found information that needs to be updated in the wiki? Or have a suggestion for a new feature? Or maybe you found a bug? Want to contribute but have no idea where to start? Send me a message over Discord, my username is valky5.