前提
1.client和server之间或多或少存在网络延迟,需要提前做好对时,并在网络环境发生变化时校正时差。国内的公网通信,非跨网的情况下,一般在120ms左右。本地的网络会好一些。
2. 要努力防止外挂,如果是以client的通知为主,也要做抽查,或者全部都校验。
3. 应用DR技术,在没有收到位置更新包的同时,client视野中的其他client按照游戏规则运动。
4. 控制位置同步的频率,减少网络流量。
以client为主的处理流程:
server只做简单校验,不做逻辑运算,优点是比较平滑,但是尽管有校验,还是不可避免会有安全性的问题:
1. client登录之后,与server做对时计算时差。
2. 位置数据包内容有:当前位置、速度、方向、时间戳。
3.client发送位置数据包给server。发包的触发条件有两个:超过了DR的阈值和定时tick触发,如果没有到定时时间但是超过了阈值,也应该发送。
4.server收到位置数据后,首先根据游戏规则校验是否合法,不合法则拉回合法的位置。然后根据时差,预测client当前的状态,并把这个计算得到位置数据广播给相关的client(包括client自己)。
5. client收到位置数据包后,根据时差,计算得到经过了延迟,现在实际的位置信息。
6.client收到的位置数据是属于其它玩家的:需要将当前模拟的玩家的位置修正到最新的位置,为了避免瞬移现象,一个简单的方法是预测一段时间之后(比如一秒后)的状态,用一条直线运动去修正。即,设想一秒后这个玩家在哪里,然后反推回现在应该用什么速度运动可以在一秒后到达那个地方。在对方玩家网络环境不好的情况下,采用这种算法会使得这个玩家在游戏画面上的速度突然加快一下,不过比瞬移会好很多。
7.client收到的信息是属于自己的,即server认可的自己的状态(并广播给别人了)。如果有误差,则是由于server的预测补偿和网络延迟的误差造成的。如果误差超过了设定的阈值,就直接跳转过去,否则不处理。
以server为准的处理流程:
以server的计算和模拟为主,client只在变化速度或者方向的时候,通知server,特点是安全性高,逻辑简单,但是server的cpu消耗大:
与以client为主的处理流程不一样的是第3步:server的计算也由两个触发条件,一是server定时做的server_move这种操作,来模拟计算并更新所有client的位置信息;二是收到client的速度或者方向改变的通知包。在满足这两个条件之一的情况下,server就应该计算得到client当前的位置信息,并广播通知到相关的玩家。
写在后面:
没有做过mmo,所以对这块的同步机制还处于摸索的阶段。看了网上不少文章,为了游戏的体验感,似乎更倾向于采用客户端为主的位置同步。具体的情况还需要通过阅读代码和写测试用例来确定。
参考文章:
http://blog.codingnow.com/2012/03/dev_note_12.html
http://blog.csdn.net/stanjiang2010/article/details/5660292
http://cjmxp007.blog.163.com/blog/static/3547383720098149046971/
http://www.cppblog.com/keigoliye/archive/2009/09/10/95830.html
http://www.joynb.net/blog/archives/108#more-108