【转】MMO即时战斗:地图角色同步管理和防作弊实现

---转自CSDN

一、前言

        无论是端游、页游、手游如果是采用了MMO即时战斗游戏模式,基本都会遇到同屏多角色实时移动、释放技能、战斗等场景,于是自然也需要实现如何管理同屏内各种角色的信息同步:例如角色的位置、以及角色身上的装备、时装、buffer等状态的实时切换。同步在网络游戏中是非常重要的,它保证了每个玩家在屏幕上看到的东西大体是一样的,解决同步问题的最简单的方法就是把每个玩家的动作都向其他玩家广播一遍,这里其实就存在一些问题:1向哪些玩家广播,广播哪些消息;2如果网络延迟怎么办。角色的定义一般包括人物、怪物、宠物、NPC等,由于这各种角色在地图上基本处于随时不规则移动并且各种属性信息也处于不断变化中(例如:变身、穿脱装备,甚至使用隐身药水),所以需要实现地图的区块上各种角色的列表管理、切换地图、进出区块管理,实时同步角色的位置信息,以及附近角色的属性信息变化到游戏内相应的玩家身上,而且这些信息的同步需要实时,否则基本就失去了即时战斗的意义。一般会采用长连接的方式,方便实时推送交互信息。同时由于MMO网络游戏环境的复杂性,管理好角色信息的同时还需要保证游戏的公平性,防止作弊、外挂,例如:判定人物的移动速度异常或者瞬间移动,纠正人物释放技能的时间间隔等,相信只要在公网运营过的游戏都多少会遇到防作弊的问题。本文主要结合参与开发并在外网运营了几年的一款MMORPG游戏做讨论和分析,游戏规模国内最高同时30w在线,同区最高上w人,相信会有一定的实战参考意义,当然也有讨论和改进的空间,这也是写这篇文章的主要目的。

二、地图以及角色管理

        无论是3D还是2D游戏:既然是即时地图战斗,那就自然有空间的概念,于是就产生了地图,一般游戏内玩家最经常发生的交互也是在地图上面发生的。mmorpg的地图一般会有固定的一些属性:例如:地图的宽度、高度、最大角色数、地图上面怪物的AI、以及常用的九宫格划分区块大小等等属性。地图宽高度用于控制地图的大小,最大角色数用于控制地图的最大承载容量,防止过载,影响玩家体验。例如:图1对地图的部分关键属性进行定义

2.1地图区块划分

        通常的游戏玩法:地图上面的玩家在地图里面只需要看到视野内周围发生的事情,并不需要关心不同地图,甚至相同地图离自己很远的地方此刻正在发生的实时场景,即使要关心,一般也是通过聊天公告等信息同步,并不需要收看现场直播)。于是,对地图采用分而治之的方法,把每张地图进行区块切分,定义好区块的大小,例如图1采用正方形的划分方法,规定每个区块的边长为6,一般区块的大小不会经常进行随意变动(除非在一些特殊的副本地图里面,该值如果进行了变化则需要进行特殊处理)这就是地图区块的概念。于是每个在线玩家在地图上面都会被定位到属于自己的区块,而当玩家在地图上面移动,则会在不同的区块之间进行来回的切换。同时,玩家在地图里面必然需要实时看到周围地图发生的场景,一般采用九宫格的方式,如图2,3.:也就是说会实时同步包括玩家所在区块在内的周边9个区块的角色信息给予相应的玩家,理论上玩家只能看到9宫内发生的事情。

2.2地图管理

        划分好了地图区块之后,地图的管理至少还要包括:a阻挡的信息:包括静态阻挡和动态阻挡:角色移动的同时需要考虑地图区块里面的阻挡信息(例如:来自角色阻挡、来自地图固定建筑的阻挡等)b角色管理:需要管理地图上面角色实时信息,并且维护各个区块的最新角色实时列表信息:用于九宫格内玩家信息的同步。对于进入地图固定区块的玩家需要实时同步自己的信息给予附近的玩家,告诉他们有角色进入视野了,相反也要同步区块周围的角色信息给该玩家,同时,对于离开地图区块的玩家,需要同步信息告诉附近的玩家离开视野的消息,保证下一帧该角色不会再出现在该区块上。而处在同个9宫格内的玩家,也需要互相同步属性信息,保证看到的是最新的角色属性变化位置信息等;并且地图上面的NPC、怪物等角色自动刷新也需要地图逻辑来处理,例如怪物死亡之后,需要处理怪物退出游戏世界,一般还要让怪物经过一段时间自动复活,重新加入地图,另外还有地图上面怪物的AI,会在另外一篇文章单独讨论。

        具体角色在地图上面管理代码的实现:针对所有角色我们首先采用定时刷新的机制,在所有的角色身上绑定定时器,例如:在GamePlayer,GameMonster,GameNpc定时触发刷新机制:根据玩家实时所在的地图比较前后所在的区块是否一致,如果不一致,自然就需要处理附近玩家有角色进出视野的信息。例如:角色A定时触发了刷新机制,发现已经从地图亚特兰蒂斯区块99进入到了亚特兰蒂斯98区块,这时,自然就要重新计算玩家的九宫格区块变化,通知相关有区块信息变化上面的地图角色位置信息:并且需要实时维护一份每个区块每张地图上面的角色列表,这样做的目的:作为地图管理者,有必要知道当前我的地图上到底都有谁,常用于玩家附近的聊天,玩家同地图的聊天,并且根据玩法一般还有地图刷怪通知该地图所有玩家的信息等需求。另外,单独针对玩家的位置信息管理,则还跟游戏的特定玩法有关系,例如可以飞地图的游戏,则当玩家实时切换地图之后,则会直接触发进出区块视野的信息,而并不需要等到定时器触发来更新角色位置信息,还有玩家重新登录或者退出游戏,自然而然也要实时处理相应的位置同步信息;还有玩家换装、使用技能、上下坐骑等都即时发消息通知九宫格内的玩家同步属性信息

三、人物的移动

        对于mmorpg,玩家的移动几乎无时不在,并且相对于怪物的移动,宠物的移动等,玩家的移动更加核心,更加复杂不可控。特别是在大规模团战中,玩家会经常移动,于是需要管理好地图上玩家的移动,如果管理不好,则会出现大规模的外挂等,严重影响游戏的公平性,对于整个游戏也几乎是毁灭性的打击

3.1人物移动实现方法

        通常对于游戏内玩家的移动有几种处理方法:1客户端只通知服务器要移动的位置,但并不需要经过后台的验证就直接开始移动了,通常服务器需要对最终客户端移动的位置进行校验,如果没有该步检测,那外挂就可以为所欲为了2客户端每一次移动都需要通过服务器的验证,然后再进行移动,该方法在网络延迟的情况下,会变得比较不流畅,给玩家带来很不爽的感觉。方法1同样存在问题:同步的误差,特别是在网络延迟特别严重的时候:比如有一个玩家A向服务器发了条指令,说我现在在P1点,要去P2点。指令发出的时间是T0,服务器收到指令的时间是T1,然后向周围的玩家广播这条消息,消息的内容是“玩家A从P1到P2”有一个在A附近的玩家B,收到服务器的这则广播的消息的时间是T2,然后开始在客户端上画图,A从P1到P2点。这个时候就存在一个不同步的问题,玩家A和玩家B的屏幕上显示的画面相差了T2-T1的时间,要解决该问题,参考了之前的一篇文章,大致的内容如下:“有个解决方案:预测拉扯,首先要定义一个值叫:预测误差。然后需要在服务器端每个玩家连接的类里面加一项属性,叫latency,然后在玩家登陆的时候,对客户端的时间和服务器的时间进行比较,得出来的差值保存在latency里面。还是上面的那个例子,服务器广播消息的时候,就根据要广播对象的latency,计算出一个客户端的CurrentTime,然后在消息头里面包含这个CurrentTime,然后再进行广播。并且同时在玩家A的客户端本地建立一个队列,保存该条消息,直到获得服务器验证就从未被验证的消息队列里面将该消息删除,如果验证失败,则会被拉扯回P1点。然后当玩家B收到了服务器发过来的消息“玩家A从P1到P2”这个时候就检查消息里面服务器发出的时间和本地时间做比较,如果大于定义的预测误差,就算出在T2这个时间,玩家A的屏幕上走到的地点P3,然后把玩家B屏幕上的玩家A直接拉扯到P3,再继续走下去,这样就能保证同步。更进一步,为了保证客户端运行起来更加smooth,我并不推荐直接把玩家拉扯过去,而是算出P3偏后的一点P4,然后用(P4-P1)/T(P4-P3)来算出一个很快的速度S,然后让玩家A用速度S快速移动到P4,这样的处理方法是比较合理的,这种解决方案的原形在国际上被称为(Full plesiochronous),当然,该原形被我篡改了很多来适应网络游戏的同步,所以而变成所谓的:预测拉扯”

方法1实现:进行人物移动管理,需要定义以下相应的移动消息:具体的消息定义如下

(a)MSG_PLAYERMOVINGPOSTOSERVER //客户端向服务器端发送移动中玩家位置改变

(b)MSG_PLAYERMOVINGPOSANDDIRTOSERVER, //移动中玩家位置和朝向改变

(c)MSG_PLAYERPOSTOSERVER,//原地不动玩家的位置消息

(d)MSG_PLAYERPOSANDDIRTOSERVER,//原地不动玩家的位置和朝向消息

        消息a和b负责向服务器同步人物需要移动到的目标位置和朝向信息,服务器需要对该位置信息进行阻挡、状态判断等合法性检测通过后,则同步角色位置信息到9宫格内的其它角色,相反如果失败例如移动到阻挡里面,则需要通知客户端纠正位置。消息c和d则同时用于前后台校验玩家的位置信息,例如角色一定时间内移动后最终停下来的位置。

四、防作弊

        常用的前后端消息加密,以及客户端加壳的机制几乎已经是通用的做法,所以这里不做重复,而且再高明的加密或者加壳几乎都有被破解的可能,但这些机制依然要坚持使用,至少可以提高作弊的成本,可以延长游戏的寿命,下面再描述我们目前除了消息加密和加壳之外采用的方法

限制客户端发送移动消息的频率:一般游戏内玩家并不需要进行太过于频繁的移动,就算需要频繁的移动客户端也可以对移动进行合并处理再上报移动位置信息,所以对于频繁的移动消息完全可以当做非法请求不处理。目的用于防止外挂封包频繁的发送移动消息,进行非法的快速移动(例如运营中发现玩家使用变速齿轮等插件,用于抢掉落宝箱等场景,会有玩家进行瞬移到宝箱附近拿走物品,这时候守门的人就崩溃了,严重影响了游戏的公平性)

移动距离检测:记录客户端每次发送移动消息的服务器时间间隔,根据人物的正常移动速度,算出合法的移动范围(一般需要加上一定的误差,由于网络的延迟等原因,不可能做到100%精确),如果发现不正常的移动速度,一般先采用和平的方法,让该移动消息失效。目的用于防止外挂封包发送不符合人物移动速度的位移信息

消息时间校验:使用外挂的玩家,例如变速齿轮等插件,而且变速齿轮可以调整倍数,所以一般可以尝试出游戏的检测频率,因此必须采取手段防止玩家使用该插件。分析出变速齿轮的原理,一般是通过修改API函数GETTICKCOUNT和TIMEGETTIME,骗过了游戏和程序的定时器导致游戏和程序速度被改变。服务端发送时间种子到客户端.客户端做个差值.举个例子:服务端发来的种子是timeGetTime()=2000,客户端本地取时间是timeGetTime()=1000那么差值就是1000客户端所有的协议中增加时间字clienttime=timeGetTime()+1000到服务端。服务端取当前时间对这个时间做个容错校验.容错范围需要你自己调节.一般最好设大点.不然容易误判.

五、运营中遇到的问题和优化空间

5.1服务器性能瓶颈

        即时战斗类游戏一般都会设计有跨服战、国战等这样的玩法,会遇到某时段同屏角色数非常多的特殊场景,这时候大量的角色战斗中移动和释放技能,上下坐骑、必然会造成消息量暴增,服务器压力骤增。以线上运营的游戏为例,解决办法:

        首先,对峰值期间的消息进行统计分析,对频繁发送并且流量大的消息进行重点监测,例如:分析出来大量角色移动进入区块,同步角色信息包括人物身上的时装,坐骑,宠物、装备等,会有一个峰值。但游戏中一般大规模团战的地图中,玩家一般最先关心的是敌人的动向位置信息,反而对人物的坐骑,时装,装备等信息可以延后,于是可以对某些特殊的场景例如国战地图,跨服战地图进行特殊的刷新机制进行优化,当区块内角色数到达一定数量后,同步信息只同步人物位置,模型等信息,减少消息的流量

        其次,为了防止高峰时期服务器处理消息量过大,待处理消息队列以及发送队列拥挤,造成雪崩。对消息进行分级别定义,定义消息的时候进行消息级别定义,目前分为低、中、高三种消息类型,并且限制每种类型在等待处理的消息队列中的最大个数,每种消息类型在队列中大于特定的值,则直接丢弃,不处理。例如:服务器ping消息,人物跳跃等则可以定义为优先级低的消息,同理对于服务器需要发送出去的消息包也进行分级

5.2刷钱刷经验

        一般外网运营一段时间的游戏很多都会遇到刷钱刷经验的bug,也许一些没有交易系统或者休闲类的游戏不会遇到,不过反正我们遇到了,就算没遇到做好预防措施也是必要的。解决方案是:请数值策划定制好根据游戏玩法角色对应一天最多能获得多少经验和金币,由服务器进行合法性检测,如果超过了阀值则必须采取处理措施。我们模仿了现实社会,给游戏设计了一张监狱地图,监狱顾名思义就是给犯法的人准备的,游戏里面发现有作弊,或者刷钱刷经验等的行为都会自动被传送到该地图,该地图没有传送点,只能一直呆在里面不能打怪升级也不能交易等诸多限制,进入该地图的玩家只有等坐牢时间到期了或者通过客服申诉成功,才会被传送出该地图

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • GameRes游资网发布, 文 /韦易笑 手游页游和端游的服务端本质上没区别,区别的是游戏类型。 类型1:卡牌、跑...
    colourstar阅读 1,568评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 文章是我转载的,没找到原作者地址。 介绍 作为一个程序,你想过网络多人对战游戏是怎么做出来的吗? 从外行的角度来看...
    齊葩阅读 2,257评论 0 14
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,796评论 25 707
  • 感觉眼睛有点点不对,明天再画一幅底稿。怕上色毁所有 后面的是重新画好的,麻烦老师帮忙看看哪个好点,谢谢
    悠悠何文阅读 711评论 3 0