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

【转】MMO即时战斗:地图角色同步管理和防作弊实现的更多相关文章

  1. [转] MMO即时战斗:地图角色同步管理和防作弊实现

    一.前言 无论是端游.页游.手游如果是采用了MMO即时战斗游戏模式,基本都会遇到同屏多角色实时移动.释放技能.战斗等场景,于是自然也需要实现如何管理同屏内各种角色的信息同步:例如角色的位置.以及角色身 ...

  2. 一款已上市MMO手游地图同步方案总结

    1. 客户端地图格子的相关知识 在2.5D的MMO游戏里,角色是通过3D的方式渲染,2D的地图是通过2D的方式显示,所以在客户端一般会有三个坐标系: a) 3D坐标系:所有需要3D渲染的角色和光效,都 ...

  3. 【转】一款已上市MMO手游地图同步方案总结

    转自游戏开发主席 1. 客户端地图格子的相关知识 在2.5D的MMO游戏里,角色是通过3D的方式渲染,2D的地图是通过2D的方式显示,所以在客户端一般会有三个坐标系: a) 3D坐标系:所有需要3D渲 ...

  4. RDIFramework.NET ━ 9.9 角色权限管理 ━ Web部分

    RDIFramework.NET ━ .NET快速信息化系统开发框架 9.9  角色权限管理 -Web部分 角色权限管理模块主要是对角色的相应权限进行集中设置.在角色权限管理模块中,管理员可以添加或移 ...

  5. RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2->WinForm版本新增新的角色授权管理界面效率更高、更规范

    角色授权管理模块主要是对角色的相应权限进行集中设置.在角色权限管理模块中,管理员可以添加或移除指定角色所包含的用户.可以分配或授予指定角色的模块(菜单)的访问权限.可以收回或分配指定角色的操作(功能) ...

  6. RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2->Web版本新增新的角色授权管理界面效率更高、更规范

    角色授权管理模块主要是对角色的相应权限进行集中设置.在角色权限管理模块中,管理员可以添加或移除指定角色所包含的用户.可以分配或授予指定角色的模块(菜单)的访问权限.可以收回或分配指定角色的操作(功能) ...

  7. Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理

    这是本人第一次写,写的不好的地方还忘包含.写这个的主要原因是想通过这个来学习下EF的CodeFirst模式,本来也想用AngularJs来玩玩的,但是自己只会普通的绑定,对指令这些不是很熟悉,所以就基 ...

  8. Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理10

    今天把用户的菜单显示和页面的按钮显示都做好了,下面先来个效果图 接下来说下我实现的方法: 首先我在每个方法前面都加了这个属性, /// <summary> /// 表示当前Action请求 ...

  9. MYSQL管理之主从同步管理

    原文地址:MYSQL管理之主从同步管理 作者:飞鸿无痕 MYSQL管理之主从同步管理 MYSQL主从同步架构是目前使用最多的数据库架构之一,尤其是负载比较大的网站,因此对于主从同步的管理也就显得非常重 ...

随机推荐

  1. 嵌入式 Linux 学习 之路

    1. 嵌入式 Linux  (首先百度了一下) 结果没有 看到 有信息的内容.2017年2月17日10:06:51 (嵌入式Linux 英文名:embedded Linux 简称 eLinux,Git ...

  2. Java关于NIO类的详解

    一.IO与NIO的区别: 前提我们先说一说java IO: Java中使用IO(输入输出)来读取和写入,读写设备上的数据.硬盘文件.内存.键盘......,根据数据的走向可分为输入流和输出流,这个走向 ...

  3. MySQL 开启事件 使用定时器调用存储过程

      mysql定时器是系统给提供了event,而oracle里面的定时器是系统给提供的job.废话少说,下面创建表:create table mytable (id int auto_incremen ...

  4. youku客户端

    文件结构 config import os IP_PORT = ('127.0.0.1',8080) BASE_DIR = os.path.dirname(os.path.dirname(__file ...

  5. 开发自己的网上支付案例代码(易宝支付php)

    1.简单的图解(如上所示) 易宝支付与支付宝是不一样的,但也有类似之处,支付宝是专门为淘宝软件开发的一套机制,资金会在中间支付公司(支付宝)停留,等待顾客确认,当顾客确认后,才会真正扣钱.而易宝支付时 ...

  6. SQL注入的浅尝辄止

    简单的说,SQL注入就是通过在前端页面输入SQL语句,导致系统暴露异常信息在前端页面显示,非法者通过这些异常信息获取数据库的相干信息,为攻击系统做准备.

  7. 高并发下,HashMap会产生哪些问题?

    HashMap在高并发环境下会产生的问题 HashMap其实并不是线程安全的,在高并发的情况下,会产生并发引起的问题: 比如: HashMap死循环,造成CPU100%负载 触发fail-fast 下 ...

  8. 用turtle库显示汉诺塔问题的过程

    用turtle库显示汉诺塔问题的过程 一.什么是汉诺塔问题? 一座汉诺塔,塔内有3个座A.B.C,A座上有n个盘子,盘子大小不等,大的在下,小的在上,如图所示.把这n个盘子从A座移到C座,但每次只能移 ...

  9. Python学习4——print打印

    print():  在控制台输出变量的值: print打印完后换行: print(123) # 完整模式:print(123,end="\n") 希望打印完不换行: print(1 ...

  10. Python递归二分法

    # lst = [4, 56, 178, 253, 625, 1475, 2580, 3574, 15963] # 时间复杂度. n# # 让用户输入一个数n. 判断这个n是否出现在lst中# n = ...