-
Notifications
You must be signed in to change notification settings - Fork 10
Multiplayer
Please try refreshing the page if the video does not load. The visual glitch you see on client disconnect has been resolved.
Multiplayer.Preview.mp4
The 2D Top Down genre includes a client-authoritative multiplayer setup, demonstrating how player positions update on each other's screens.
Note
Each packet comes with a small overhead—either 1 or 2 bytes, depending on reliability configured—and a one-byte opcode to identify its purpose. Everything else in the packet is strictly the data we need to send.
Below is an example of a client packet. The client uses this packet to inform the server of its position. To actually do something with Position on the server, override the Handle method from ClientPacket.
public class CPacketPlayerInfo : ClientPacket
{
// The NetSend parameter indicates the order of what gets sent first
[NetSend(1)]
public string Username { get; set; }
[NetSend(2)]
public Vector2 Position { get; set; }
}Below is an example of a server packet. The server uses this packet to inform each client about the position updates of all other clients. To actually do something with Positions on the client, override the Handle method from ServerPacket.
public class SPacketPlayerPositions : ServerPacket
{
[NetSend(1)]
public Dictionary<uint, Vector2> Positions { get; set; }
}Note
If you need more control on how data is sent in a packet, read this.
// Player.cs
Net.Client.Send(new CPacketPlayerInfo { Username = playerUsername, Position = playerPosition });// GameServer.cs
Send(new SPacketPlayerPositions { Positions = Positions }, peerId);Lets say you want to [NetSend] this PlayerData but you don't want to send the PrevPosition.
public class PlayerData
{
public string Username { get; set; }
public Vector2 Position { get; set; }
[NetExclude] // [NetSend] will ignore PrevPosition
public Vector2 PrevPosition { get; set; }
}-
Do not directly access properties or methods across threads unless they are explicity marked as thread safe. Not following thread safety will result in random crashes with no errors logged to the console. Things on the client thread should stay on the client thread and things on the server thread should stay on the server thread. If you need to communicate between them use the existing ConcurrentQueues.
-
A common oversight is using one data type for writing and another for reading. For example, if you have an integer
playerCountand you write it withwriter.Write(playerCount), but then read it as a byte withplayerCount = reader.ReadByte(), the data will be malformed becauseplayerCountwasn't converted to a byte prior to writing. To avoid this, ensure you cast your data to the correct type before writing, even if it feels redundant.