游戏服务器开发经验小结

(1)为每一个存放在共享内存的对象,编写Init()、Resume()、Reload()函数;

(2)服务器进程重启进行共享内存恢复时,谨记恢复存放在共享内存中的对象数据的同时,也不要忘了同时恢复指向共享内存数据的指针;

(3)用gcc编译时,选择-Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers选项,并试图消除所有告警;

(4)尽管使存放在共享内存中的数据不要为指针或引用,以免共享内存恢复数据时再来额外的开发复杂度;

(5)尽量多开发一些GM指令,以便于黑盒测试;

(6)仔细查看每一个ERROR级别(游戏运营时的日志级别)的日志内容是否丰富,以便于游戏运营期间查找可能出现的程序异常;

(7)主动严重关注运营中游戏服务器的每一条ERROR级别日志,认真分析程序可能存在的隐患,而不要等到客服报告玩家的投诉时再查;

(8)通过分析和解决错误日志内容,来加强对程序逻辑的理解;

另外,还有一些通用准则:

(1)技术的东西,永远不要一知半解;

(2)和代码交朋友,认真对待每行代码;

(3)精益求精,用苛刻的眼光对待自己写的代码;

(4)碰到问题,永远不要拖延,按事情的轻重缓急,力争早点解决;

 

看代码的感受

这几天,持续阅读项目代码,有几点感受;

1)一个软件项目,参与开发的人越多,整个项目的代码越有凌乱不堪的危险,需要尽可能地在项目的各个阶段进行不断的整理,也就是我们常说的重构,这是一个特别重要的事情,项目参与的人数越多,开发人员的经验越是参差不齐,越要这样做;

2)在保证正确完成需求的基础上,尽量把代码写得更美一些,诸如接口的有效提炼、对象的有效抽象、数据结构的有效选取、代码的有效组织等等;

3)对全局需求(代码)的了解,有助于完善局部需求的设计与实现;

思考游戏服务器的tick机制

游戏服务器程序内部都会统一设计所谓的tick机制,这个机制一般来说有两个用途,一是许多业务模块都会有定时处理的需求,如:技能Buff计时、时间道具检查、定时给玩家收益(打坐定时回血和蓝,跳舞定时回经验等)等等;二是游戏服务器内部会有一些日常主动驱动的事件,如:怪物移动、玩家移动等,这些需求都需要用到这个tick处理,夸张一点说,游戏服务器业务逻辑的处理绝大部分都会有涉及到tick处理的需求。

那这个相当重要的tick机制是如何实现的呢?目前我们采用的是在主程序大循环中,每一次循环取一次当前系统时间并保留上次进入tick处理时的时间,然后拿这两个时间相比较,若大于tick设定的间隔时间(如:200ms),则进入tick函数处理。这个tick函数中,注册了系统所有业务模块需要定时处理的接口。于是,在大循环中每一次tick调用,就会将系统所有定时处理的接口都处理一遍。于是,问题便也随之而来了… …

显而易见的问题是,所有的定时处理都放在一起调用,这会造成CPU的峰值瞬间拉高,并且也会造成server消息处理的能力下降(因为tick处理的这段时间,本质上是可以作为server对消息的延时处理时间),对于这个问题,我们也有显而易见的处理方法,即将各个业务模块的定时时间进行分类,大致可以分为200ms、500ms、1s、3s、20s、30s、60s等适合各业务需求的定时间隔,这样每一次tick调用时,就不会同时有许多模块一齐处理了,这可以在一定程度上平滑CPU的处理曲线。但也无法避免会在某个时间点,同时有许多(甚至所有)业务模块定时处理的情况,所以,我在想,是否还有其它更好的处理办法呢?

首先想到的是,是将各个业务模块的定时间隔进行更精确和合理的分类,比较理想的情况是:使各个定时间隔互不包含,即各个间隔之间不要存在整除的关系,如:300ms、500ms、1100ms等,这个可以做一个测试,看一下这样修改后,CPU的处理是否更平滑一些。

由于在linux下中,系统定时器是由SIGALRM信号来实现的,而一般游戏server为了稳定等原因,都屏蔽了linux的许多信号操作,所以,一般就采用自定义的定时器来实现tick机制了,只是我们的这种机制是否还有更好的实现方式呢?这的确是一个值得思考的问题,毕竟,tick处理在游戏server中占了相当大的比重。

当然,只有让每一个业务模块,每一次tick处理的时间尽可能缩小到最短,那么,tick处理对于CPU的消耗就会减轻到最小了!

MMORPG中技能战斗系统的技术分享

今天下午参加了公司兄弟项目组的一个技术分享会,主题是关于MMORPG游戏中的技能系统设计的,有几点体会和思考,先记录下来了!

(1)技能施法时,client只有一个上行的请求施法包,后续施法的过程全由server来驱动下发施法各阶段的结果信息,如吟唱、效果伤害、命中信息等等;

(2)弹道类技能是由server计算飞行时间,并不考虑飞行后的轨迹,若此时目标有移动,则client会做目标跟随的处理;

(3)技能学习:由秘籍来获得技能,一本秘籍包含多个技能,被动技能不影响主动技能的属性;

(4)Buff系统与技能系统是相互独立的,相互之间有接口各自的进行访问;

(5)玩家施法作群攻目标选定时,也是由server来完成,这时是从玩家自己的视野里搜索,而无需再搜一次动态区域(格子32*32);

(6)技能效果由一个主效果+N个Buff效果组成;

(7)Buff对象区分玩家和怪物,其存储结构独立出来放在内存池中,在施法者需要时再根据目标类型来添加;

(8)特别小心:在作技能效果计算时,尽量避免有轮循的处理,因为,这个这个很耗CPU;

思考题:关于技能引发的位置同步问题

(1)对于改变目标(玩家)移动速度的技能,可能会带来位置不同步的问题,即server下发速度改变的包时,目标玩家可能正在移动,从而导致server和client的位置不一致?

答:对于这个问题,一般是通过移动系统自身的位置同步策略来解决的,即移动系统发现client和server位置不一致时,通过一定的策略来补偿速度慢的一方,从而在目标玩家在接来的一定时间内达到位置平衡。

(2)类似性质的问题还有给目标加冰冻、定身等Buff,也可能带来位置不同步的问题?

答:这个问题暂也还没有好的解决方案,目前的做法是当目标中定身Buff时,client立即表现定身,即定在原地,并将此时的位置信息带给server,server检验合法后设置这个位置,解冻后client为继续玩家移动(若玩家是移动中被定身住的话)。