在游戏服务器&我计划制作的客户端,从长远来看,我将要处理很多数据包。我想知道如何处理我的不同数据包的最佳做法是什么。
我的数据包有效负载将以PacketID开头。
创建一个扩展Packet的单独类并在那里处理逻辑是不是一个好主意?例如Packet001Login?从长远来看,这将给我一个很多类。
制作巨大的切换声明是否更好?我对此表示怀疑。
这是我没想过的最佳方式吗?
非常感谢任何建议。
答案 0 :(得分:2)
如果,您确实需要在服务器端进行计算时间,那么您应该采用一种技术来为不同的包类型创建原型。
为了说明这一点和想法,我给你一些像课程描述的UML
UML:
class PacketPrototype
+ PacketPrototype(PacketType)
+ addData(DataType, Bitlength, ...)
+ deserilize(Bitstream stream) : ReceivedPacket
+ serilizeThis() : ToSendPacket
+ getPacketType() : int
你还需要一个包含所有PacketPrototypes的类,并决定每个PacketPrototype对象的Type,应该使用Prototype来对数据进行deserilize。
你需要一个知道每个PacketPrototype的类,我称之为PacketPrototypeHolder
class PacketPrototypeHolder
+ register(PacketPrototype)
+ getPrototypeForPacketType(int Type) : PacketPrototype
关于设置时间的协议如下
PacketEnemy00 = new PacketPrototype(0)
PacketEnemy00.addData(Types.Int, 5) // health
PacketEnemy00.addData(Types.String, 16) // name
...
这意味着类型为0的数据包由一个5位长的int和一个最大长度为16个字符的字符串组成。
我们必须在安装后将PacketPrototype添加到PacketPrototypeHolder
PacketHolder.register(PacketEnemy00)
如果服务器或客户端接收到我们读取数据包类型的内容,那么我们就这样做了 (您可以从比特流中读取数据)
Type = Bitstream.readInt(5)
Prototype = PacketHolder.getPrototypeForPacketType(Type)
ReceivedPacket OfReceivedPacket = Prototype.deserilize(Bitstream)
// we need here a switch/if statement to determine how to handle the reading of the data
switch(Type)
{
case 0: // PacketEnemy00
Prototype.deserilize
调用从数据流读取数据并将其放入ReceivedPacket对象,从那里您可以使用索引操作或命名访问来访问数据。
作为一个例子,我用索引
来做 int UnitHealth = OfReceivedPacket.getInt(/* index, we want the 1st int */0);
string UnitName = OfReceivedPacket.getString(/* index, we want the 1st string */0);
and so on...
break;
...
}
因此,我有效地将switch语句从网络层内部移动到应用程序/使用层。
要删除开关,您需要采用数据驱动方法。但它在引擎中的实现比硬编码方法更复杂。