最近完成了邮箱的功能。

邮箱的设计参考了 mmzb 的设计,基于一套 msgsrv 来实现。msgsrv 是一个消息中转的服务,这个服务是为了简化玩家之间消息传递的过程。比如邮箱要向一个离线玩家发信,为了避免对离线玩家的数据进行修改,会通过 msgsrv 发送到玩家对应的 msgbox 里。玩家上线后,会自动查询自己的 msgsrv,检索未读消息。当玩家上线时,会主动在 msgsrv 中发起订阅。每当有新的消息进入,msgsrv 会直接发送到玩家所在的 agent 上,实现实时通知。唯一例外的情况,是全局消息的发送。一条全局消息发送的时候,只是向一个全局的队列里插入一份数据。玩家只会在登录时检索一次这个全局队列,并记住自己的检索位置。缺点是全局消息的通知不及时,需要玩家离线再上线才能收到。需要实时的消息,可以通过聊天系统解决。

这个设计相对来说还是比较简单的。但是,这个功能的提交,涉及到 46 个文件。我提交 Pull Request 的时候,自己都惊到了。当然,这其中并不是全部都是代码的修改。这些修改可以简单的分为三块。一块,是配置之类的修改,比如新增服务的参数,新增服务的数据存储对应的数据库定义,玩家数据库对象新增的结构描述。这里占了 7 个文件。第二块,是在 lualib 里提供的新 api,为其他服务提供新功能的入口。其中还包含一些趁手的工具函数,方便以后功能的开发。这里占了 8 个文件。第三块是大头,实现了 msgsrv 的逻辑部分,以及邮箱的业务代码。这一块有 31 个文件,是这个 PR 的主要部分。

除了玩家自身的成长系统外,其他系统基本都涉及到两部分。一部分,是挂在玩家的 agent 身上的,另一部分,则是对公有数据的修改。先看看 agent 的部分。agent 身上需要有对应服务的 api,供客户端通过 sproto 协议来远程调用。还需要有对应的 api,供相应的 skynet 内服务的调用。一般还会有一套额外的 gm api,供客户端进行测试的时候使用。这三组 api,功能覆盖的面差不多,最终都会操作玩家身上的数据,通知到玩家的客户端。就这次提交的邮件 PR 来看,这些 api 占住了 7 个文件。玩家数据部分的管理,是由几个类完成的。这里占用了 3 个。总的来看,agent 身上一共改了 15 个文件,稍微有点多。

剩下的文件,集中在对公有数据的修改上,即 msgsrv 的主体部分。其中有 4 个是用于执行功能测试的测试脚本,暂且不提。剥开 msgsrv,首先是一层 command,然后是对全局消息的管理器,对个人 msgbox 的管理器,对这两者的管理器,以及管理 msgsrv 服务的启动脚本、退出脚本、gm 指令。这里的优化空间应该比较大,按照 CRUD 的四字法划分,个人消息管理器和全局消息管理器都有着多个 R,多个 U,正交性不够好,还要锤炼一下。

优化现有的设计,主要目标是希望修改能够更简洁而清晰。不再因为添加一个小小的功能,就产生数十个文件的修改。对我来说,涉及的文件数量太多,就经常记不住细节,导致 api 改动的时候,常常出现漏改漏测。目前看到的可以优化的地方,就是各种自发现。比如 lualib 里面提供一个通用的调用 api 封装,只要传入方法名和服务名,就能自动调用对应服务的 command api。数据结构的定义,能够实现自动发现,不需要修改引用文件。(待续)