Kevin Lynx 6.22.2010
MMORPG中,玩家的移动主要逻辑都放在客户端进行,包括自动寻路和响应玩家的操作,服务
器在这里担当一个被动角色。但是服务器端的玩家数据却是真正的被其他逻辑模块参考的数
据。
在这样一种C/S主从关系中,如何保证C/S两者各自维护的玩家坐标数据的一致性?为了保证
数据的一致性,我们需要进行数据的同步。而导致数据不同步(不相同),也就是C/S之间
玩家的坐标不一样,主要来源于两大原因:C->S数据的网络延迟、S->C数据的网络延迟。考
虑到这两个重要的因素,首先需要尽量减少C/S之间数据的交互。
在一般的逻辑模块中,客户端发送一个请求到服务器,服务器作了验证后返回验证结果,客
户端接收验证结果继续之前的逻辑。这对于MMO中诸如物品操作而言是足够的,但无法应用
于玩家移动。
这里的做法是:客户端每走一步,都发消息(网络封包)给服务器,服务器做验证;客户端
停止走动后,通知服务器,服务器返回自己保存的坐标,客户端在这个时候才使用服务器端
的数据同步一次本地坐标。其操作序列如下图:
-----------------------------------------------------------------
Client Server
移动、本地坐标改变 ----> 验证C/S之间的坐标是否差距过大,
验证失败通知客户端停止移动
停止移动 ----> 验证同上
同步本地坐标为服务器坐标 <---
-----------------------------------------------------------------
此外,客户端保存一个请求计数,每一次发送一个移动请求时,递增该计数;服务器收到该
请求后,验证成功,返回一个消息,客户端收到此回应消息后递减该计数。当该计数超过某
个配置数值后,客户端将忽略玩家的移动操作。客户端还可以将玩家的多个移动操作合并为
一个,即,只在角色到达玩家最后一次点击的坐标时,才发送停止移动消息给服务器。
配合请求计数机制,当C->S的消息出现延迟太久时,此时也意味着请求计数过大,客户端会
强迫玩家等待;服务器终于收到消息后,逐个处理,直到处理完后,客户端的请求计数恢复
时,玩家才可继续移动。同样,当S->C的消息(只考虑停止移动的消息回应)出现延迟时,
这个时候客户端很可能在本地做了另一次移动操作,在终于接收到上一次移动操作的服务器
端回应时,因为这个时候客户端毫无条件地将本地数据同步为服务器端发过来的数据,那么
,出现这种情况后,客户端角色就会出现拉回去的现象。这里的一次移动,可能是多个地图
格子的移动,一般为角色当前坐标到玩家点击的目标坐标。