Reputation: 13
I'm using Lidgren.Networking to send data between server and clients in a client/server architecture. I have created a Packet class to use when sending packets over the network.
Packet.cs
public abstract class Packet : IPackable
{
public abstract void PackIntoNetMessage(NetOutgoingMessage msg);
public abstract void PopulateFromNetMessage(NetIncomingMessage msg);
}
IPackable.cs
interface IPackable
{
void PackIntoNetMessage(NetOutgoingMessage msg);
void PopulateFromNetMessage(NetIncomingMessage msg);
}
Then I have application specific packet classes like this
public class PositionPacket : Packet
{
public int PosX { get; set; }
public int PosY { get; set; }
public override void PackIntoNetMessage(NetOutgoingMessage m)
{
m.Write((byte)Networking.PacketTypes.PositionPacket);
m.Write(PosX);
m.Write(PosY);
}
public override void PopulateFromNetMessage(NetIncomingMessage m)
{
PosX = m.ReadInt32();
PosY = m.ReadInt32();
}
}
Sending the packets is easy, I just create a packet and PackIntoNetMessage(msg) and then send it. But it's when I try to recieve packets I get some annoying structural problems.
I start by reading the first byte
var packetType = (Networking.PacketTypes)incomingMsg.ReadByte();
but then I have to make a switch with a case for each packet type in order the get the correct constructor.
switch (packetType)
{
case Networking.PacketTypes.PositionPacket:
incPacket = new Packets.PositionPacket();
break;
default:
incPacket = null;
break;
}
//Populate packet from net message
incPacket.PopulateFromNetMessage(incomingMsg);
This is the part that I don't like. I want to be able to make a generic packet handling system that handles any class deriving from Packet. I guess reflection wont be a good idea since it will kill the performance. How shall I structure this to make it more generic?
Upvotes: 1
Views: 1659
Reputation: 50682
The instance of the specific class needs to be created somehow so you could use reflection on start-up to fill a dictionary with all available classes that derive from Packet stored by their ids.
Creating an instance would then boil down to:
var packetTypeId = (Networking.PacketTypes)incomingMsg.ReadByte();
var incPackage = (Package)Activator.CreateInstance(packetTypes[packetTypeId]);
If you are worried about creating many, many instances and expect garbage collection cycles with big impact on your application's speed you could create a pool of objects that recycles instances. As long as you drop objects, that are no longer used, back into the pool you could prevent GC cycles.
var packetTypeId = (Networking.PacketTypes)incomingMsg.ReadByte();
Type packetType = packetTypes[packetTypeId];
Package incPackage;
if(!pool.TryGetRecycledInstance(packetType, out incPackage))
{
incPackage = (Package)Activator.CreateInstance(packetType);
}
Upvotes: 2