匹配
//請求匹配
message CM_Match {
int type; //匹配房間類型
String name; //玩家名稱
long targetPlayerId; //加入他人比賽傅蹂,目標(biāo)玩家id
}
//匹配成功
message L2RM_MatchSucc {
int roomId;
int roomType;
boolean createRoomIfNotExist; //場景中的第一個玩家為true
RoomPlayerEnt ent; //房間服需要的玩家信息
}
//業(yè)務(wù)服收到此消息創(chuàng)建房間
message R2LM_AddRoom {
int id;
int sign; //房間簽名
int type;
Date createTime;
}
//業(yè)務(wù)服收到此消息励稳,在房間銷毀前(R2LM_RemoveRoom),玩家都可以斷線重連房間服
message R2LM_AddPlayer {
long playerId;
int roomId;
int roomSign;
int roomType;
int token; //登錄令牌犬金,斷線重連時下發(fā)給客戶端
}
//客戶端收到此消息后連接房間服
message SM_RoomServerPermission {
String host;
int port;
String token; //本次登錄的令牌
}
業(yè)務(wù)服房間管理
業(yè)務(wù)服維護(hù)了房間服的Room念恍。房間服創(chuàng)建Room,業(yè)務(wù)服創(chuàng)建對應(yīng)Room晚顷,房間服銷毀Room峰伙,業(yè)務(wù)服銷毀對應(yīng)Room。其變化通過處理房間服的R2LM_AddRoom该默,R2LM_RemoveRoom等消息完成瞳氓。
在匹配規(guī)則中另外維護(hù)了MatchRoom。匹配規(guī)則認(rèn)為需要創(chuàng)建一個新的房間時栓袖,則馬上創(chuàng)建MatchRoom匣摘,當(dāng)一個玩家被匹配到某個MatchRoom中,MatchRoom中立即添加該玩家裹刮。新增過程不依賴房間服的消息音榜。
Room的作用是用于統(tǒng)計房間服的信息,玩家的斷線重連捧弃。MatchRoom用于完成匹配邏輯赠叼。兩者的作用不同決定生命周期不同,Room的生命周期由房間服決定塔橡,MatchRoom在匹配時創(chuàng)建梅割,在人滿時銷毀霜第,在房間服的房間銷毀時也會銷毀葛家。
class Room {
int id;
int sign;
RoomType type;
Date createTime;
int playerNum; //玩家數(shù)量
int watcherNum; //觀戰(zhàn)者數(shù)量
RoomServer server; //所屬房間服
}
class MatchRoom {
int id;
List<Long> playerIds;
RoomServer server; //所屬房間服
}
進(jìn)入房間服
message CM_EnterRoom {
long playerId;
String token; //登錄令牌
}
//業(yè)務(wù)服收到此消息,將玩家加入房間服玩家集合
message R2LM_PlayerEnterRoom {
long playerId;
int roomId;
int roomType;
int status; //狀態(tài) 0.游戲 1.觀戰(zhàn)
}
//場景快照
message SM_SceneSnapshot {
}
離開房間服
//業(yè)務(wù)服收到此消息泌类,將玩家從房間服玩家集合中移除
message R2LM_PlayerLeaveRoom {
long playerId;
int roomId;
String token; //登錄令牌相同才能移除玩家
}
玩家結(jié)算
//結(jié)算消息分成兩部分癞谒,第一部分在房間服計算底燎,比如排行榜
message SM_RoomResult {
根據(jù)結(jié)算面板確定...
}
//通知客戶端斷開房間服連接,返回業(yè)務(wù)服
message SM_DisconnectRoomServer {
連接業(yè)務(wù)服的信息...
}
//將結(jié)算內(nèi)容發(fā)到業(yè)務(wù)服弹砚,由業(yè)務(wù)服計算獎勵等數(shù)據(jù)
message R2LM_PlayerResult {
}
//業(yè)務(wù)服收到此消息双仍,清理玩家斷線重連的相關(guān)信息。
//房間服再次收到R2LM_AddPlayer消息才允許玩家登陸桌吃。
message R2LM_RemovePlayer {
long playerId;
String token; //登錄令牌相同才能移除玩家
}
房間結(jié)算
//房間結(jié)算朱沃,包含了所有需要結(jié)算的玩家
message R2LM_RoomResult {
}
//業(yè)務(wù)服收到此消息,清理房間服
message R2LM_RemoveRemove {
long playerId;
String token; //登錄令牌相同才能移除玩家
}
房間結(jié)算時茅诱,所有玩家必須結(jié)算逗物。
房間服消息作用
房間服發(fā)給業(yè)務(wù)服的消息主要有6個
- R2LM_AddRoom
- R2LM_RemoveRoom
- R2LM_AddPlayer
- R2LM_RemovePlayer
- R2LM_PlayerEnterRoom
- R2LM_PlayerLeaveRoom
R2LM_AddRoom/R2LM_RemoveRoom用于維護(hù)業(yè)務(wù)服的房間的創(chuàng)建和銷毀。
R2LM_AddPlayer/R2LM_RemovePlayer主要用于維護(hù)玩家能否斷線重連房間服瑟俭。
R2LM_PlayerEnterRoom/R2LM_PlayerLeaveRoom用于維護(hù)哪些玩家在房間服翎卓,以及相關(guān)狀態(tài)的修改。
玩家離開房間服的行為會導(dǎo)致房間服發(fā)送R2LM_PlayerLeaveRoom給業(yè)務(wù)服摆寄,而玩家完成一局游戲才會導(dǎo)致房間服發(fā)送R2LM_RemovePlayer給業(yè)務(wù)服失暴。
房間服線程模型
每個房間綁定到線程池中的一個線程,房間的所有業(yè)務(wù)都單線程處理微饥。
房間支持消息隊列逗扒,可以向其投遞各種消息。玩家進(jìn)入房間欠橘,玩家離開房間缴阎,玩家結(jié)算,房間結(jié)算等任務(wù)简软,都在房間線程中處理蛮拔。
第一個玩家進(jìn)入房間時,啟動房間定時器痹升,并處理房間消息建炫。房間銷毀后停止定時器,不再處理房間消息疼蛾。
class Room {
ConcurrentLinkedQueue<IRoomTask> taskQueue;
}
<b>問題:</b>
當(dāng)房間服收到L2RM_MatchSucc時肛跌,會創(chuàng)建新玩家,將玩家放入緩存察郁,如果緩存中已存在玩家衍慎,則需要銷毀已存在的玩家。銷毀玩家的任務(wù)需要投遞到房間線程中執(zhí)行皮钠,可能會發(fā)生執(zhí)行順序錯誤問題稳捆。
- 代碼順序
Player oldPlayer = playerMap.put(playerId, player);
if(oldPlayer != null && oldPlayer.getScene() != null) {
oldPlayer.getScene().removePlayerAsync(oldPlayer);
...
}
send R2LM_AddPlayer message
- 執(zhí)行順序
thread 1: send R2LM_AddPlayer message
thread 2: send R2LM_RemovePlayer message //removePlayer是異步執(zhí)行
<b>解決方法:</b>
并不糾正執(zhí)行順序,而是在R2LM_AddPlayer和R2LM_RemovePlayer消息中增加token字段麦轰。player和oldPlayer的玩家id相同乔夯,但是登錄token不同砖织。業(yè)務(wù)服通過對比token,可以知道本次R2LM_RemovePlayer是否有效末荐,如果在R2LM_RemovePlayer之前已經(jīng)收到了包含新的token的R2LM_AddPlayer消息侧纯,則忽略R2LM_RemovePlayer消息的處理。
由于執(zhí)行順序依然是異步的甲脏,在同一時間眶熬,房間服可能同時存在相同id的兩個Player。所以除了在全局維護(hù)Player集合块请,每個房間還維護(hù)了自己的Player集合聋涨,房間中需要獲取玩家通過內(nèi)部的Player集合獲取,不要通過全局的Player集合獲取负乡,因為獲取到的可能是新的Player牍白。
異常情況
L2RM_MatchSucc問題
1.玩家匹配到一個已經(jīng)銷毀的房間
解決方案
1.盡可能在房間銷毀前停止匹配,比如持續(xù)12分鐘的房間抖棘,可以在最后30s停止匹配茂腥。
2.提示錯誤。玩家手動重新匹配切省。
CM_EnterRoom問題
1.玩家不存在最岗,或登錄令牌錯誤
解決方案:報錯。
2.房間不存在
解決方案:報錯朝捆,重連業(yè)務(wù)服般渡。
3.投遞消息時房間存在,(在房間線程)執(zhí)行消息時房間不存在
解決方案:報錯芙盘,重連業(yè)務(wù)服驯用。
只匹配,但不登錄房間服的玩家如何清理
定時30分鐘檢查儒老,Player關(guān)聯(lián)的房間銷毀則清理Player蝴乔。
沒有啟動定時器的房間如何銷毀
定時30分鐘檢查,30分鐘都沒有玩家進(jìn)入則銷毀房間驮樊。