网络游戏常常需要把一个对象的属性同步到客户端去,例如物品详细信息:耐久度、堆叠数量、位置等。逻辑常常是这样的,玩家上线,服务端将某个物品的所有属性同步到客户端,为此我们会定义一个消息来做此工作,如果某个时刻物品的耐久度发生了变化,我们就需要把耐久度发送下去,这样就又存在一个同步耐久度的消息,因此我们需要为一个属性定义一个消息。那么必然面临几个问题:
- 维护的问题,每次增加和删除属性都需要:
1)定义或者删除消息
2)定义或者删除消息处理函数
3)增加或者删除属性发送相关代码 - 如果在服务器一次同步周期中,同个属性发生变化多次,将发送多个消息到客户端,这里存在一些不必要的损耗
Protobuf 的 optional field 能够帮我们很好的处理此类逻辑。看一个例子:
- message ItemInfo
- {
- optional int32 duration = 1;
- optional int32 stack = 2;
- optional int32 position = 3;
- }
ItemInfo 表示了一个物品的所有属性,在玩家登录的时候,我们可以同步一次。服务器运行时属性发生变化,我们可以这么做:
- 内部的 Item 类需要持有一个 ItemInfo 的对象,每次改变属性时调用相关的 set_ 函数
- 在一次同步周期中,发送一次 ItemInfo 到客户端,用于同步被改变的属性,之后 Clear ItemInfo 对象
通过这种做法,我们一定程度上缓解或者解决了上面所述的问题。当然,对于属性同步也可以自己实现一套类似的机制,但是很难保证能够像 Protobuf 一样漂亮。