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的消息(只考慮停止移動的消息回應)出現延遲時,
這個時候客戶端很可能在本地做了另一次移動操作,在終于接收到上一次移動操作的服務器
端回應時,因為這個時候客戶端毫無條件地將本地數據同步為服務器端發過來的數據,那么
,出現這種情況后,客戶端角色就會出現拉回去的現象。這里的一次移動,可能是多個地圖
格子的移動,一般為角色當前坐標到玩家點擊的目標坐標。