-
Notifications
You must be signed in to change notification settings - Fork 18
Sending a Packet from the Server to the Client
Valk edited this page Feb 3, 2023
·
1 revision
Sending a packet from the server to a client is much like sending a packet from a client to the server but there are a few differences.
- Instead of
CPacket
it isSPacket
- Instead of
APacketClient
it isAPacketServer
- Instead of
void Handle()
it isasync Task Handle()
(this may change later on) - Instead of
Handle()
being executed server-side, it is executed client-side
Lets create the packet
// Sometimes it is helpful to create a secondary opcode so we are not clogging up the main opcode pipeline
// Since the first opcode 'ServerPacketOpcode' is sent as a byte, there can not be more than 255 server opcodes
public enum ServerGameInfo
{
PlayerJoinLeave,
PlayersOnServer,
StartLevel,
MapPosition,
PeerId
}
public class SPacketGameInfo : APacketServer
{
public ServerGameInfo ServerGameInfo { get; set; }
// Comments are used to organize properties as this packet is a multi-purpose packet
// Only one ServerGameInfo value can be specified at a time
// PlayerJoinLeave
public string Username { get; set; }
public bool Joining { get; set; }
public byte Id { get; set; }
// PlayersOnServer
public Dictionary<byte, string> Usernames { get; set; }
// StartLevel
public string LevelName { get; set; }
// MapPosition
public Vector2 MapPosition { get; set; }
// PeerId
public byte PeerId { get; set; }
public override void Write(PacketWriter writer)
{
writer.Write((ushort)ServerGameInfo);
// Handle each opcode accordingly
switch (ServerGameInfo)
{
case ServerGameInfo.PlayerJoinLeave:
writer.Write(Username);
writer.Write(Joining);
writer.Write((byte)Id);
break;
case ServerGameInfo.PlayersOnServer:
writer.Write((byte)Usernames.Count);
foreach (var player in Usernames)
{
writer.Write((byte)player.Key);
writer.Write(player.Value);
}
break;
case ServerGameInfo.StartLevel:
writer.Write(LevelName);
break;
case ServerGameInfo.MapPosition:
writer.Write(MapPosition);
break;
case ServerGameInfo.PeerId:
writer.Write((byte)PeerId);
break;
}
}
public override void Read(PacketReader reader)
{
ServerGameInfo = (ServerGameInfo)reader.ReadUShort();
// notice Logger.Log(...) is not used directly here because Client.Log gives a nice prefix and color automatically
Net.Client.Log($"Received: {ServerGameInfo}");
switch (ServerGameInfo)
{
case ServerGameInfo.PlayerJoinLeave:
Username = reader.ReadString();
Joining = reader.ReadBool();
Id = reader.ReadByte();
break;
case ServerGameInfo.PlayersOnServer:
var length = reader.ReadByte();
Usernames = new Dictionary<byte, string>();
for (int i = 0; i < length; i++)
{
var key = reader.ReadByte();
var value = reader.ReadString();
Usernames.Add(key, value);
}
break;
case ServerGameInfo.StartLevel:
LevelName = reader.ReadString();
break;
case ServerGameInfo.MapPosition:
MapPosition = reader.ReadVector2();
break;
case ServerGameInfo.PeerId:
PeerId = reader.ReadByte();
break;
}
}
public override async Task Handle()
{
// if there are no uses of await keyword in the Handle() method then add 'await Task.FromResult(0);' at the very bottom
switch (ServerGameInfo)
{
case ServerGameInfo.PlayerJoinLeave:
HandlePlayerJoinLeave();
break;
case ServerGameInfo.PlayersOnServer:
HandlePlayersOnServer();
break;
case ServerGameInfo.StartLevel:
await HandleStartLevel();
break;
case ServerGameInfo.MapPosition:
HandleMapPosition();
break;
case ServerGameInfo.PeerId:
HandlePeerId();
break;
}
}
// ...
}
Send the server packet to all clients but the host
Net.Server.SendToEveryoneButHost(ServerPacketOpcode.GameInfo, new SPacketGameInfo
{
ServerGameInfo = ServerGameInfo.StartLevel,
LevelName = LevelManager.CurrentLevel
});
Send the server packet to a specific client specified by peer
server.Send(ServerPacketOpcode.GameInfo, new SPacketGameInfo
{
ServerGameInfo = ServerGameInfo.PlayersOnServer,
Usernames = server.Players.ToDictionary(x => x.Key, x => x.Value.Username)
}, peer);
Send the server packet to everyone but a specific client specified by peer ID
SendToOtherPlayers(netEvent.Peer.ID, ServerPacketOpcode.GameInfo, new SPacketGameInfo
{
ServerGameInfo = ServerGameInfo.PlayerJoinLeave,
Username = username,
Joining = false,
Id = (byte)netEvent.Peer.ID
});