服務器——UID

一、介紹

在rpg這類遊戲中,有大量的實體存在,實體包括玩家、NPC、怪物、坐騎、寵物等等,每天實體有一個id,這個id是在實體創建的時候生成的,我們稱之爲uid,通過uid我們可以獲取到實體對象。(對於玩家實體它們還有一個id,是在玩家註冊賬號的時候db生成的id,我們稱之爲dbid,用於數據庫中記錄玩家唯一標記。)

 

二、uid設計

uid是實體的唯一標記,通過uid我們需要查詢到實體對象。uid設計重要考慮的是怎樣通過uid查詢到實體對象。這裏有幾種設計方案:

方案一:map存儲

map的key值爲uid,value爲實體對象指針。查詢時間複雜度lg(n),map底層是紅黑數當實體創建或刪除的時候紅黑樹需要進行調整,當實體刪除或創建頻繁的時候性能消耗也會增大。

方案二:數組索引

uid是服務器自己生成的,那我們可以讓uid從1連續遞增生成,通過索引搜索效率可以爲常數級。當有實體創建的時候可以一次創建一批,供後續實體創建使用,實體刪除可以將uid回收用於後續新創建的實體使用。

實現過程,定義一個數組,用於記錄當前服務器中創建的實體,通過uid可以直接搜索到實體對象指針,再定義一個列表用於記錄空閒的實體,當我們需要一個uid對象的時候,我們去列表中獲取一個,如果列表爲空,我們將數組進行擴容,並將新創建的空閒實體添加到列表中。

總結,通過方案一和方案二對比,方案二效果跟好。

 

三、類結構演示

3.1 結構定義

下圖爲一個實現例子。

  • CGlobalServer: 服務器全局對象,服務器的主對象。
  • CEntityWorld:實體世界,管理整個服務器的實體。
  • IEntity:實體接口。
  • ConcreteEntity:一個具體的實體,可能是NPC、怪物、坐騎、寵物等等。
  • SEntity:一個實體序列號和實體指針組合,我們可以將其轉爲一個64位整數,也就是定義的uid。

一個uid定義如下,UID 和 SEntity結構是等價的可以相互轉換。

typedef LONGLONG UID;
struct ___UID
{
	DWORD dwSerialNo;	// 序列號,不可逆,單通過此ID也可以標識對像
	DWORD dwHandle;		// 對像句柄,可重複的(此成員需放後面,uid小點)
};

// 分解出序列號
#define ANALYZEUID_SERIALNO(uid)	(((___UID *)&uid)->dwSerialNo)

// 分解出實體句柄
#define ANALYZEUID_HANDLE(uid)	(((___UID *)&uid)->dwHandle)

 

3.2 uid構建和或取對象

uid構建

一個具體的實體ConcreteEntity,創建完成會把自己添加到實體世界中,也就是調用函數CEntityWorld::Add(),CEntityWorld::Add()會調用BuildUID(),爲實體構建一個uid。構建uid過程,先判斷m_listUsableEntity中是否還有對象,如果有彈出一個用於當前新創建的實體,如果沒有先對數組m_pEntityArray進行擴容(可以一次加1W個),將之前數據添加到新的數組中,並將新創建的對象添加到m_listUsableEntity中,用於新創建的對象。當一個對象使用完畢,將對象uid添加到m_listUsableEntity中用於後續創建的實體對象。

通過uid獲取實體對象,直接看代碼,直觀清晰。

IEntity * CEntityWorld::Get(LONGLONG uid)
{
	if(uid == INVALID_UID)
	{
        return NULL;
	}

	// 解析
	DWORD dwSerialNo = ANALYZEUID_SERIALNO(uid);
	DWORD dwHandle = ANALYZEUID_HANDLE(uid);

	// 句柄越過了,非法
	if(dwHandle >= m_dwHandleMaxCount)
	{
        return NULL;
	}

	IEntity * pEntity = m_pEntityArray[dwHandle].pEntity;
	if(pEntity == NULL)
	{
        return NULL;
	}

	// 要判斷序列號
	if(m_pEntityArray[dwHandle].dwSerialNo != dwSerialNo)
	{
        return NULL;
	}

	return pEntity;
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章