天天看點

最後一戰(LastBattle)伺服器源碼分析2——中心伺服器(CentralServer)中心服CS:

中心服CS:

作為遊戲的核心伺服器,中心服承擔着除戰鬥外的所有遊戲功能,包括房間比對,場景服(SS)戰鬥及玩家的管理控制,郵件系統,玩家實體建立和管理,Kernel核心管理,資料存儲與緩存,遊戲日志生成等。

最後一戰(LastBattle)伺服器源碼分析2——中心伺服器(CentralServer)中心服CS:
房間比對:
class CCSMatchMgr
{
public:
    ...
    INT32 TeamStartMatch(IMatchPlayer* pPlayer);//開始比對
    bool TeamStopMatch(IMatchPlayer* pPlayer);//結束比對
    void Update(int64_t tUTCMilsec,int64_t tTickSpan);
    ...
private:
    map<UINT32,ICSMatchList*>   mAllMatchList[eMatchType_Total];//不同類型的比對清單
    map<UINT32,CCSMatchTeam*>   mAllTeamMap;//記錄所有正在比對的隊伍資訊
};
           

該類是CCSBattleMgr的成員變量,在伺服器啟動時建立,并在一個定時器中周期性的調用重新整理函數:

該重新整理函數中根據mAllMatchList數組中存儲的用戶端發來的不同類型的開始比對的玩家資料,調用各自類型的update函數進行比對。最終在比對函數:

中,根據函數

選取負載最小的SS,并根據該SS的id在CS上建立CCSBattle來管理本場戰鬥,然後将本次比對的玩家及機器人資料通過消息eMsgToSSFromCS_CreateBattle發送給該SS,SS接收到資訊後開始建立CSSBattle,加載地圖資訊,設定玩家和AI資訊,建立玩家CSSUser等,然後通知用戶端開啟戰鬥。

場景服(SS)戰鬥及玩家的管理控制:
//戰場資訊類
class CCSBattle
{
private:
    ...
    BattleType             m_Type; //戰場類型
    EBattleMatchType       m_MatchType;//比對類型
    map<UINT64,CCSUser*>   m_UserMap;//玩家資料
    map<UINT32,SAIRobot*>  m_AIRobots;//機器人資料
    SMapLogicCfg*          m_MapLogicCfg;//地圖配置
public:
    ...
    //遊戲開始發送所有資料給場景服
    INT32 Start();
    //發送消息給用戶端
    INT32 BroadcastMsgToAllUser(google::protobuf::Message& sMsg,int n32MsgID);
    //向場景服發送消息
    INT32 PostMsgToBattleSS(google::protobuf::Message& sMsg,int n32MsgID);
    INT32 PostMsgToSS_NotifyUserIsOnline(CCSUser* pUser,bool IsOnline);
    //向網關服發送消息
    INT32 PostMsgToGS_NotifyCombineUserNetInfoToSS(CCSUser* piUser,ICSSSInfo* piSSInfo);
    INT32 PostMsgToGS_NotifySplitUserNetInfoToSS(CCSUser* piUser,ICSSSInfo* piSSInfo);
    ...
};

typedef hash_map<UINT64,CCSBattle*> BattleMap;
//場景服戰場資訊管理類
class CCSBattleMgr
{
private:
    UINT64                      m_un64MaxBattleID;//目前最大戰場唯一id
    BattleMap                   m_cAllBattleMap;//根據戰場id存儲目前存在的戰場資訊
    CCSMatchMgr*                m_pMatchMgr;//戰場比對管理資料
    map<UINT32,CCSBattleRoom*>  m_BattleRoomList;//遊戲房間清單
public:
    ...
    //向場景服通知玩家線上資訊
    INT32 NotifyBattleSSUserIsOnline(CCSUser* piUser,bool isOnline);
    //向場景服發送資訊
    INT32 PostMsgToBattleSS(UINT64 un64BattleID,google::protobuf::message& sMsg,int n32MsgID);
    ...
public://建立房間進入遊戲
    ...
    //建立遊戲房間
    INT32 AskCreateRoom(CCSUser* piUser,UINT32 un32mapId,const string& stPwd,bool isRestart,UINT32 rePostion=0);
    //遊戲房間添加玩家
    INT32 AskAddRoom(CCSUser* piUser,UINT32 un32mapId,const string& stPwd,bool isRestart,UINT32 rePostion=0);
    //遊戲房間開始遊戲
    INT32 OnBattleRoomStart(CCSBattleRoom* pRoom,CCSUserListMap& sList,map<UINT32,UINT32>* aiRobots,UINT32 mapID);
    ...
public://随機比對進入遊戲
    INT32 RemoveMatchUser(CCSUser* piUser);//從準備比對隊列中移除該玩家
    //對準備比對隊列中的玩家進行比對
    void  OnBattleMached(CCSUserListMap& pList,map<UINT32,UINT32>* aiRobots,...);
    void  OnBattleMached(EBattleMatchType type,UINT32 mapId,...);
private:
    INT32 OnMsgFromRC_DO(ICSRCInfo* piRCInfo,...);//接收及處理來自遠端控制端的消息
    INT32 OnMsgFromGC_DO(ICSRCInfo* piRCInfo,...);//接收及處理來自用戶端的消息
    INT32 OnMsgFromSS_DO(ICSRCInfo* piRCInfo,...);//接收及處理來自場景服的消息
    ...
};
           
  • 玩家進入遊戲比對分為自由比對,建立房間方式和引導方式,三種方式最終都是建立相應類型的CCSBattle,并将該戰場的玩家,機器人,地圖等資訊發送給場景服來建立戰場(具體見房間比對解析)。同時保持和用戶端(通過GS)及場景服的連接配接,同步及接收各種資料。
郵件系統:
struct MailDBData
{
    INT64   objIdx;  //郵件所屬玩家id
    INT32   mailId; //郵件Id
    ...
    INT64   n64CreateTime;  //郵件建立時間
    INT64   n64EndTime; //郵件過期時間
  
    string  mailTitle; //郵件主題
    string  mailContent;//郵件内容
    string  mailGift;//郵件贈送附件
    ...
};

class CCSMailMgr
{
    INT32                                         m_curtMaxMailIdx;//目前的全服郵件id最大值,用于生成唯一郵件id
    std::map<INT32,MailDBData>                    m_mapGameMail;//根據郵件id存儲全服郵件資料
    std::map<INT64,std::map<INT32,bool>>          m_IfHasSendMail;//臨時的延時郵件
    //個人郵件資訊,根據個人id存儲郵件id清單,具體郵件資訊需根據郵件id在m_mapGameMail擷取
    std::map<INT64,std::map<INT32,tagMailState>>  m_mapPersonalMail;
public:
    ...
    bool addGameMail(const MailDBData& mail);//添加郵件資料
    ...
    bool closeOrGetMailGift(CCSUser* pUser,INT32 mailId);//領取贈送郵件附件并删除郵件
    ...
private:
    void addPersonalMail(const MailDBData& mail);//添加個人郵件
};
           
  • CCSMailMgr是玩家資料管理類CCSUserMgr的成員變量,用于管理玩家郵件的發送,提取,删除等操作。
  • m_curtMaxMailIdx在伺服器開啟連接配接上資料庫時,會根據目前資料庫中的郵件id來設定該值,放置郵件id重複。
  • 郵件主要資訊存儲在MailDBData,贈送附件mailGift根據EMerchType類型提取金币,鑽石,道具等不同附件。
玩家實體建立和管理:
class CCSUser
{
private:
	EUserPlayingStatus	 m_eUserPlayingStatus; //玩家是否線上
	SUserDBData			 m_sUserDBData;//玩家基本資料(存檔)
	TIME_MILSEC		     m_OfflineTime;//下線時間
	
	SUserNetInfo	     m_sUserNetInfo;//玩家網絡資料
	TIME_MILSEC		     m_tGCLastPing;//用戶端最近一次ping時間
	CCSUserBattleInfo	 m_sUserBattleInfoEx;//玩家戰鬥資料
	IRoomPlayer		     m_tRoomPlayer;//建立房間進行遊戲時的個人房間資料
	IMatchPlayer		 m_tMatchPlayer;//自由比對時的個人比對資料
	CTaskMgr*		     m_cTaskMgr;//任務資料管理
	map<UINT64, SUserRelationshipInfo>	m_cAddFVec;//好友資料
	int64_t								m_TimerID;//個人資料定時儲存定時器id
	...
	
	stringstream   m_RuneBagStream;//符文背包資料
	stringstream   m_RuneSlotStream;//符文位置資料
public:
	//上線操作
	void	 OnOnline(SUserNetInfo& netinfo,GCToCS::Login &pLogin,bool isFirstInDB,bool isFirstInMem,bool isReLogin=false);
	//下線操作
	void	 OnOffline();
	//強制踢下線
	INT32	 KickOutOldUser();
	//重置用戶端最後ping時間
	INT32	 ResetPingTimer();
	//加載玩家基礎資料
	INT32	 LoadDBData(SUserDBData &crsDBData);
	//加載玩家好友資料
	void	 LoadUserSNSList(DBToCS::RSinfo msg_snslist);
	//添加道具
	void	 AddUserItems(DBToCS::ItemInfo& itemInfo);
	...
};  

class CCSUserMgr
{
private:
	typedef	map<UINT64, CCSUser*>	UserMap;
	UserMap						m_cUserGUIDMap;//所有玩家資料管理
	UserMap						m_cUserOnlineMap;//線上玩家資料

	typedef map<string, CCSUser*> UserNickNameMap;
	UserNickNameMap				m_cNickNameMap;//按綽号分類的玩家資料
	map<SUserNetInfo, CCSUser*>	m_cUserNetMap;//按網絡連接配接分類的玩家資料

	Concurrency::concurrent_queue<Buffer*>	m_DBCallbackQueue;//網絡線程與邏輯線程通訊消息隊列
	CThreadSafeObejctPool<Buffer>	        m_DBCallbackQueuePool;//網絡Buffer池

	DBActiveWrapper*	m_UserCacheDBActiveWrapper;//用于系統對玩家資料存儲的資料庫線程
	DBActiveWrapper*	m_CdkeyWrapper;// 用于全局資料操作的資料庫線程
	vector<DBActiveWrapper*>	m_pUserAskDBActiveWrapperVec;//用于玩家主動請求操作的資料庫線程

	INT64	    m_MaxGuid;//目前伺服器最大GUID,但遊戲裡的GUID是合成的,以保證所有CS Server唯一
	set<string>	m_AllNickNameSet;//所有玩家昵稱集合,所有關于昵稱的操作可以通過此表來操作!
	map<UserCombineKey, UINT64>	  m_AllUserName2GUIDMap;//所有玩家使用者名,guid表,如果玩家登陸 通過CS,SDK,Username查到對應guid
	CCSMailMgr					  m_MailMgr;//郵件管理類
	std::stringstream			  m_SaveUserStream;//玩家資料儲存資料流
	
	DBActiveWrapper&			GetNowWorkActor();// 擷取目前負載最小的DB線程
public:
	//注冊消息處理回調
	void	RegisterMsgHandle(SSMsgHandlerMap& m_SSMsgHandlerMap, GSMsgHandlerMap& m_GSMsgHandlerMap, GCMsgHandlerMap& m_GCMsgHandlerMap, RCMsgHandlerMap& m_RCMsgHandlerMap);
	//玩家存儲DB線程回調
	void	UserCacheDBAsynHandler(Buffer*& pBuffer);
	//玩家請求回調
	void	UserAskDBAsynHandler(Buffer*& pBuffer);
	//玩家線上處理
	INT32	OnUserOnline(CCSUser *pcUser, const SUserNetInfo &crsUserNetInfo);
	//玩家離線處理
	void	OnUserOffline(CCSUser *pcUser);
	//處理玩家請求的資料庫操作
	bool	PostUserAskMsgToDBThread(google::protobuf::Message& sMsg, int n32MsgID);
	//處理緩存資料請求的資料庫操作
	bool	PostUserCacheMsgToDBThread(INT64 guidIndex, const string& sqlStr);
private:
	//添加玩家資料
	INT32					AddUser(CCSUser *pcUser);
	//移除玩家資料
	INT32					RemoveUser(CCSUser*& pcUser);
	//處理來自GateServer的消息
	INT32					OnMsgFromGS_DO();
	//處理來自用戶端的消息
	INT32					OnMgrFromGC_DO();
	//處理來自場景服的消息
	INT32					OnMsgFromSS_DO();
	//處理來自遠端控制端的消息
	INT32					OnMsgFromRC_DO();
	...
};
           
  • 玩家實體CCSUser在玩家在中心服上線時建立,并加入到管理類CCSUserMgr,玩家資料在下線時會存檔,并從管理類中清除析構。
  • 整體遊戲資料分為玩家資料和全局遊戲資料,通過兩個不同的資料庫線程進行自動存儲操作,玩家自身的對資料庫操作交由其他的自定義資料庫線程,這個資料庫線程數量根據配置決定,每次選取負載最小的線程處理資料。
  • 中心服的玩家資料會根據來自用戶端,GateServer,場景服和遠端控制端的資料進行更新,并及時進行存檔。
Kernel核心管理:
class CCSKernel
{
public:
	CCSSSInfo*			m_pcSSInfoList;//連接配接的場景服清單
	CCSGSInfo*			m_pcGSInfoList;//連接配接的網關服清單
	SSSNetInfo*			m_psSSNetInfoList;//場景清單網絡連接配接資訊
	SGSNetInfo*			m_psGSNetInfoList;//網關清單網絡連接配接資訊
	SRCNetInfo*			m_psRCNetInfoList;//遠端控制端清單網絡連接配接資訊
	CHAR				m_szRemoteConsolekey[c_n32DefaultRemoveConsoleKeyLen];//遠端管理端密碼

	CBattleTimer		m_BattleTimer;//定時器管理類
	SCSKernelCfg		m_sCSKernelCfg;//配置資料
	DWORD				m_RunCounts;//用于記錄伺服器運作幀數情況
	TIME_TICK			m_LastReport;//伺服器運作日志最新記錄時間

	SSMsgHandlerMap		m_SSMsgHandlerMap;//場景服消息系統資料庫
	GSMsgHandlerMap		m_GSMsgHandlerMap;//網關服消息系統資料庫
	GCMsgHandlerMap		m_GCMsgHandlerMap;//用戶端消息系統資料庫
	RCMsgHandlerMap		m_RCMsgHandlerMap;//遠端控制端消息系統資料庫
private:
	INT32	LoadCfg();//加載配置
	INT32	UnloadCfg();//解除安裝配置
	void	ProfileReport(int64_t tUTCMilsec, int64_t tTickSpan);//記錄運作日志
public:
	//主循環
	void	MainLoop();
	//添加定時器
	int64_t	AddTimer(HeartbeatCallback pHeartbeatCallback, int64_t interval, bool ifPersist);
	//移除定時器
	void	RemoveTimer(int64_t timerID){m_BattleTimer.RemoveTimer(timerID);}
};
           

CCSKernel主要用于

  • 加載中心伺服器的配置,并負責監聽;
  • 連接配接其他伺服器,注冊與其他伺服器的互動的消息;
  • 記錄目前連接配接的網關服,場景服和遠端控制端網絡資訊;
  • 提供定時器功能;
  • 記錄伺服器運作日志;
資料存儲與緩存:

見資料存儲篇

遊戲日志生成:

見日志系統篇

繼續閱讀