手游游戏服务器逻辑框架

1 背景

首先,要回答一个问题:

我们为什么要专门为手机游戏专门定制设计一个游戏服务器逻辑框架?

坦白地说,公司自研游戏做了这么多年,事实上互娱已经沉淀了一批相当成熟的组件,如:解决底层网络通信的Tconnd、解决进程间通信Tbus、解决协议加解包的Tdr等等,但我们发现,这些组件绝大多数都是与业务无关的基础组件、服务和库。而与游戏业务紧密相关的逻辑框架,可能每个项目组都有自己的一套,这一方面源于,不同游戏业务,的确需求本身有较大的差别,很难用一套可复用性很强的逻辑框架包打天下;另一方面,也可能受限于项目本身的开发进度压力,端游有相对充裕的开发时间,但由于游戏系统繁多,平摊下来,每个系统的开发时间也不多,而页游和手游的开发进度就更紧一些,逻辑框架这块也没太多时间来作整理了。

2 现状

以stan经历过的工作室里三款游戏为例:微连、微胖和微塔。

三款游戏在业务逻辑处理上,均各自使用不同的一套框架,风格迥异。如果要说相同点,则是均使用C/C++来作业务逻辑的实现。微连和微胖均以tapp作基础来搭建框架,而微塔则是完全自行做的一套后台框架。

考虑到手游开发周期短,迭代速度快,发布频率高等特点,如果延用目前的逻辑框架,无论是上述三款游戏的哪一种,均难以解决如下几个问题:

(1)开发复杂度较高

这里的复杂度包括语言本身的复杂度、开发效率、代码可读/可维护性等。

(2)运维部署代价较高

从代码编译到上线部署,整个周期都比较长,虽然目前的逻辑框架基本上都采用了共享内存保存玩家核心数据,以便于进程重启后数据即时恢复的机制,用来实现“热更新”的效果,但这实际上是以牺牲开发复杂度来作代价的。

(3)系统可靠性

实事求是地说,要写出可靠性的代码,根本上还是取决于写代码的“人”。但由于C/C++本身是属于偏底层的语言,对开发者的要求客观上要更高一些。但即使经验丰富的开发者,也难免不犯内存越界、内存泄漏、堆栈溢出等诸多令人抓狂的错误。

有鉴于此,结合业内同行朋友成熟项目的经验,我们选择用Lua与C/C++混合编程的方式来实现游戏业务逻辑。

3 新的解决方案

新改进的逻辑框架基本可以解决上述提到的三个问题,至于为什么选择用Lua,这个业内基本上已有了一些共识,可以看这里,互娱魔方工作室也有项目已经在应用 ,看这里。故这个问题在此不再赘述。

接下来,我们探讨一下解决方案的具体实现方法。

3.1 边界

混合编程面临的一个问题是:如何界定不同语言之间的处理边界。对于我们来说就是,Lua能干什么,该干什么?C/C++需要做什么?

为此,我们在实现需要遵行的一些原则有:

  • 网络消息的收发、加解包、DB读写、日志读写、玩家对象池管理等涉及到有一定CPU开销或底层处理的操作均由C/C++来承担;
  • 有复杂交互流程的逻辑,由Lua来实现,如:一个业务协议流程涉及到多个SS交互;
  • 有单一重复逻辑的需求,由Lua来实现,如:任务、关卡、副本等;
  • 系统配置文件由Lua来实现;
  • 其它比较模糊的业务系统,我们会根据如下几个因素来综合权衡:开发效率、性能、两种语言的交互调用频率等;

3.2 框架外貌

(1)GAMESVR加载Lua配置文件进行进程参数以及业务逻辑参数配置;

(2)GAMESVR加载Lua逻辑脚本,根据CS请求,运行不同的逻辑脚本;

(3)GAMESVR可以通过修改Lua逻辑脚本进行热更新;

3.3 框架处理流程

手游框架处理流程

3.4 Lua配置文件处理思路

Lua的一种重要用途是作为配置语言

XML层次分明,写起来太复杂;ini配置不够灵活;其他配置需要自己开发

Lua作为配置文件编写起来简单,解析也方便,更重要的是在Lua协程框架中,很多情况是Lua协程读取配置文件,而不需要其他接口便可直接读取,天然的结合,使用起来非常方便。

遇到的问题:

(1)一份配置文件,C++中需要调用并且Lua业务逻辑脚本中也需要调用如何处理?

在GAMESVR中,建立一个ConfModule,ConfModule加载Lua配置文件到本模块中的Lua虚拟机,并把配置文件需要的字段解析到本模块的成员变量中,对外提供GET接口进行访问,对于LuaTaskMgrModule也同样加载该lua配置文件,方便Lua业务逻辑脚本中的调用。

 

(2)lua配置文件便捷的解析方式

采用lua_dostring方式,将需要的参数按lua语句方式复制给一个变量,然后通过lua_tostring、lua_tointeger、lua_tonumber将其解析出来,lua_dostring方式速度较慢,但该模块只是在GAMESVR初始化时候解析一次,并将解析出来的数据存入模块的成员变量中,后续数据访问通过提供的GET接口,解析完后关闭lua虚拟机,我们认为该方式在解析速度上可接收。

 

3.5 C++网络收发包处理思路

目前GAMESVR中存在三个异步回调点:

  • TBUS
  • TCAPLUS
  • LIBCURL
  • lua协程框架需要将task_id存入异步交互数据中,并且需要在响应包中能够原封不动的带回该task_id;
  • TBUS可以将task_id放入包头的seq_id字段;
  • TCAPLUS可以通过TcaplusService::TcaplusServiceRequest中的SetAsyncID将task_id存入,并在响应包时,通过TcaplusService::TcaplusServiceResponse的GetAsynID获取task_id

LIBCURL需要封装,使得CurlClient支持缓存task_id的机制;

4 写在后面的话

目前用新的逻辑框架,重写了好友关系链Server和GameSvr账号登录验证模块,可以用微塔老客户端完成账号登录全流程。

虽然新设计的逻辑框架还有诸多可完善的地方,但初次尝试应用,我们已感受到它带来的变化,比如:重写的好友关系链Server代码量比原来缩减了近三分之一,代码量减少的很明显的好处就是:代码更简洁,可读性更高(客观说,微塔原来的代码也写得不错,可读性也比较好)。

在后续项目的开发实践过程中,我们还需不断优化、完善新设计的逻辑框架,让其可用性更高、可复用性更强,相信经历咱们新项目的洗礼,新的逻辑框架能成为咱们产品中心游戏服务器开发的一把利器。