MMORPG 中场景服务的抽象
MMORPG 中,场景信息同步是很基础而必不可少的服务。这部分很值得抽象出来,专门做成一个通用的服务程序。
此服务无非提供的是,向有需求的对象,同步场景中每个实体的状态信息。那么,我们分解需求,可以看到两点,一是提交状态,二是同步状态。
每条状态信息其实是由三部分构成,状态对象名(key)、状态值(value)、时间。
玩家、NPC、场景中的可变物品,其实都有可改变的状态。比如对象的位置坐标是最常见的状态。其它的状态还有玩家或 NPC 做的动作,玩家离线,上线,等等。
可以有若干数据源向这个服务提供数据,如果借用 zeromq 中的模式的话,这个服务应该使用一个 PULL socket 收集数据。它获取从不同数据源 PUSH 来的,key-value 。然后打上时间戳,储存在内存中。
这个服务另外提供一个发布服务,向所有订阅者广播其收到的状态改变信息,每条信息包括推送来的 key-value 以及附加上去的时间戳。
第三,这个服务应该提供一个请求应答服务,除了订阅模式外,允许别人索取从指定的 timeline 到现在的所有状态。这多用于新的订阅者上线,它需要获取历史上的状态信息。
综上,这三条看起来就是一个 twitter 的基础服务,但缺少了对象之间的关注关系。嗯,在这个简化系统中,这点是可以省略的。另外,状态并不是 tweet 。我们在意的是对状态的修改,而不是同一 key 下的历史上所有状态值。比如,我们只关心一个玩家当前最新的位置,而不关心他历史上在哪里。
这个玩意能做什么?除了同步玩家和 NPC 的位置外,还可以作为战斗系统的基础。比如,玩家做一个攻击动作,可以做为一个状态提交。对于显示来说,场景中的其它玩家都应该看到他做这个动作。但一个额外的战斗模块也可以通过订阅场景,了解到这个玩家做了攻击动作。
之后,战斗模块通过其它途径获得这个攻击动作的具体含义(会产生多少伤害等等),进行运行,得到结论。而进入战斗状态的玩家,可以通过订阅战斗模块发布的信息来获得细节。
嗯,这只是举例说明其一可以想到的用途而已。如果我的归纳没有错误的话,提供上面基本服务的设施,可以做的事情很多,却只需要实现定义好的简单需求了。再列一下:
一个 PULL socket,获得格式为 key-value 的状态信息。收到后加上 time 储存。
一个 PUB socket ,一旦受到 1 里面获得的状态信息,即可连同 time 发布出去。
一个 REP socket ,收到 REQ 请求(一个 time 值),把从这个时间点之后的所有状态信息反馈回去。
下一步,我们看看怎么增强这个服务,解决更复杂的问题:场景很大怎么办?
我们的状态信息还需要增加一个部分,位置。即 key-value-position 。
我们可以增加发布点,把场景分成若干区域,每个区域树立一个灯塔。position 本身会被匹配到临近的几个灯塔上。每个灯塔都是一个子发布点。
增加这样一个服务 :提供一个 REP socket ,收到 REQ 请求(一个position 值)后,返回若干临近的灯塔 id 以及灯塔的信号半径 。然后,用户可以选择订阅这些灯塔。当发现自己的视野即将超出灯塔覆盖后,可以重新索取更换一批灯塔。
关于状态的删除。当物品消失,玩家下线,npc 死亡 等等事件发生后,相关状态,变得只有时间线最后一条信息有意义了。这个时候我建议提交 k/v 对的时候将 v 设置为空,表示把这条状态删除。这样以后用户在请求时就不用获取到无用信息了。