傳奇源碼分析-客戶端(游戲邏輯處理源分析三)


6. 接收怪物,商人,其它玩家的消息:
ProcessUserHuman:(其它玩家—服務器處理)
CPlayerObject->SearchViewRange();
CPlayerObject->Operate();
遍歷UserInfoList列表,依次調用每個UserInfo的Operate來處理命令隊列中的所有操作; pUserInfo->Operate()調用m_pxPlayerObject->Operate()調用。根據分發消息(RM_TURN)向客戶端發送SM_TURN消息。GameSrv廣播新玩家上線(坐標)的消息。向該新玩家發送玩家信息(等級,裝備,魔法,攻擊力等)。
玩家,移動對象:
1. 遍歷m_xVisibleObjectList列表,所有(玩家,商人,怪物)發送調用AddProcess
(RM_TURN向周圍玩家發送消息)。
地圖:
2.遍歷m_xVisibleItemList,發送AddProcess(this, RM_ITEMSHOW消息更新地圖。
3.遍歷m_xVisibleEventList,發送AddProcess(this, RM_SHOWEVENT

ProcessMonster線程:(怪物—服務器處理)
GameSrv服務器在ProcessMonster線程:創建不同的CMonsterObject對象,並且加入xMonsterObjList列表和pMapCellInfo->m_xpObjectList列表中,然后再調用CMonsterObject::SearchViewRange()更新視線范圍內目標,根據g_SearchTable計算出搜索坐標,轉換為相應的地圖單元格,遍歷所有可移動生物,加入m_xVisibleObjectList列表,調用Operate;Operate遍歷m_DelayProcessQ列表,過濾出RM_DOOPENHEALTH,RM_STRUCK和RM_MAGSTRUCK三個事件(恢復生命值,攻擊,魔法攻擊),並處理。
ProcessMerchants線程:(商人--服務器處理)
1). 遍歷g_pMerchantInfo結構(根據nNumOfMurchantInfo數量)。得到商人類型相關的地圖,創建商人對象,設置不同的編號,坐標,頭像及所屬地圖。在該地圖中加入該商人,且在g_xMerchantObjList商人清單中加入該商人。
2). 遍歷g_xMerchantObjList, SearchViewRange,對每個商人更新視線范圍內目標
a). 遍歷m_xVisibleObjectList,設置每個pVisibleObject->nVisibleFlag = 0;設置狀態(刪除)。
b). 搜索VisibleObjectList列表,(服務器啟動時InitializingServer加載 searchTable.tbl),根據坐標,找到相應的地圖單元格。然后遍歷pMapCellInfo->m_xpObjectList列表,判斷如果為OS_MOVINGOBJECT標志,調用UpdateVisibleObject函數,該函數遍歷 m_xVisibleObjectList列表,如果找到該商人對象,則pVisibleObject->nVisibleFlag = 1;否則判斷pNewVisibleObject對象,設置nVisibleFlag為2,設置對象為該商人實體,然后加入m_xVisibleObjectList列表中。

總結:循環列表,找出地圖單元格中的所有玩家,把所有玩家(OS_MOVINGOBJECT)加入到m_xVisibleObjectList列表中。
c). 遍歷m_xVisibleObjectList列表,(pVisibleObject->nVisibleFlag == 0)則刪除該pVisibleObject對象。
d). RunRace調用AddRefMsg 向周圍玩家發送SM_TURN和SM_HIT

客戶端收到消息后相應的處理:
1.CGameProcess::OnSocketMessageRecieve加入m_xWaitPacketQueue隊列
遍歷m_xVisibleObjectList隊列中所有移動物體(角色):
RM_DISAPPEAR 消失(SM_DISAPPEAR) ProcessDefaultPacket函數
RM_DEATH 死亡(SM_NOWDEATH, SM_DEATH)
CHero::OnDeath 其它玩家。
CActor::OnDeath 怪物。
//g_xGameProc.m_xMagicList
RM_TURN 移動
SM_TURN消息處理
遍歷m_xVisibleItemList隊列中所有移動物體(地圖):
RM_ITEMHIDE 從m_stMapItemList列表中刪除該移動對象
RM_ITEMSHOW 遍歷m_stMapItemList,如果不存在,則創建一個GROUNDITEM結構,並加入m_stMapItemList列表中。
typedef struct tagGROUNDITEM
{
INT nRecog;
SHORT shTileX;
SHORT shTileY;
WORD wLooks;
CHAR szItemName[40];
}GROUNDITEM, *LPGROUNDITEM;
遍歷m_xVisibleEventList隊列中所有移動物體(事件):
RM_HIDEEVENT
RM_SHOWEVENT


2. 部分數據未處理,加入m_xWaitPacketQueue隊列中由ProcessPacket處理。
CClientSocket::OnSocketMessage的FD_READ事件中,PacketQ.PushQ把接收到的消息,壓入PacketQ隊列中。處理PacketQ隊列數據是由CGameProcess::Load()時調用OnTimer在CGameProcess::OnTimer中處理的,處理過程為:
OnTimer -> ProcessPacket -> ProcessPacket處理m_xWaitPacketQueue隊列消息(OnSocketMessageRecieve函數中未處理的消息)。

ProcessPacket 函數處理流程:
1. 處理本玩家(SM_NOWDEATH, SM_DEATH, SM_CHANGEMAP, SM_STRUCK)
a.如果接收到消息是SM_NOWDEATH或SM_DEATH 則加入m_xPriorPacketQueue隊列。
b. 如果接收到消息是SM_CHANGEMAP則調用LoadMapChanged,設置場景。
c. SM_STRUCK 處理受攻擊(本玩家,或者其它的玩家,NPC等)。

2. 其它消息:m_xMyHero.StruckMsgReassign();
m_xMyHero.m_xPacketQueue.PushQ((BYTE*)lpPacketMsg);
判斷服務器發送來的消息ID是否相同。m_xMyHero.m_dwIdentity在登錄成功的時
候由服務器發送的用戶消息獲取的。
if ( lpPacketMsg->stDefMsg.nRecog == m_xMyHero.m_dwIdentity )
如果是服務器端游戲玩家自己發送的消息,則處理自己的消息。否則如果是其它玩家(怪物)發送的消息,遍歷m_xActorList列表, 判斷該對象是否存在,如果該不存在,則根據stFeature.bGender的類型
_GENDER_MAN: 創建一個CHero對象,加入到m_xActorList列表中。
_GENDER_WOMAN:
_GENDER_NPC: 創建一個CNPC對象,加入到m_xActorList列表中。
_GENDER_MON: 創建一個CActor對象,加入到m_xActorList列表中。
然后pxActor->m_xPacketQueue.PushQ 然后把消息壓入該對象的xPacketQueue列表中。

總結:ProcessPacket處理 CClientSocket類接受的消息(m_xWaitPacketQueue),判斷是否是服務器發送給自己的消息,處理一些發送給自己的重要消息,其它消息處理則加入m_xMyHero.m_xPacketQueue隊列中,然后再遍歷m_xActorList隊列,判斷如果服務器端發來的消息里的玩家(NPC,怪物),在m_xActorList隊列中找不到,就判斷一個加入m_xActorList列表中,並且把該消息壓入pxActor->m_xPacketQueue交給該NPC去處理該事件。
而xPacketQueue隊列的消息分別由該對象的UpdatePacketState處理,如下:
BOOL CActor::UpdatePacketState() ,BOOL CNPC::UpdatePacketState()
BOOL CHero::UpdatePacketState()。

ProcessDefaultPacket函數:
處理CGameProcess::OnSocketMessageRecieve 中 SM_CLEAROBJECT消息:
處理(SM_DISAPPEAR,SM_CLEAROBJECT)消息。
遍歷m_xWaitDefaultPacketQueue消息列表
SM_DISAPPEAR和SM_CLEAROBJECT:
遍歷m_xActorList列表,清除pxActor->m_xPacketQueue隊列內所有消息。
m_xActorList.DeleteCurrentNodeEx();從對列中刪除該對象。
CHero* pxHero = (CHero*)pxActor; delete((CHero*)pxHero);銷毀該玩家。


游戲循環處理: CGameProcess::RenderScene(INT nLoopTime)函數:
主要流程如下:
wMoveTime += nLoopTime; 判斷wMoveTime>100時,bIsMoveTime置為真。

1.m_xMyHero.UpdateMotionState(nLoopTime, bIsMoveTime);處理本玩家消息。
a. UpdatePacketState函數:
遍歷m_xPriorPacketQueue隊列,如果有SM_NOWDEATH或SM_DEATH消息,則優先處理。
處理m_xPacketQueue隊列中消息。
SM_STRUCK:
SM_RUSH
SM_BACKSTEP
SM_FEATURECHANGED:
SM_OPENHEALTH:
SM_CLOSEHEALTH:
SM_CHANGELIGHT:
SM_USERNAME:
SM_CHANGENAMECOLOR:
SM_CHARSTATUSCHANGE:
SM_MAGICFIRE:
SM_HEALTHSPELLCHANGED:

2.CheckMappedData函數:遍歷m_xActorList列表分別調用
CActor::UpdateMotionState(INT nLoopTime, BOOL bIsMoveTime)
CNPC::UpdateMotionState(INT nLoopTime, BOOL bIsMoveTime)
CMyHero::UpdateMotionState(INT nLoopTime, BOOL bIsMoveTime)
處理自己消息。

CHero::UpdatePacketState()
case SM_SITDOWN:
case SM_BUTCH:
case SM_FEATURECHANGED:
case SM_CHARSTATUSCHANGE:
case SM_OPENHEALTH:
case SM_CLOSEHEALTH:
case SM_CHANGELIGHT:
case SM_USERNAME:
case SM_CHANGENAMECOLOR:
case SM_HEALTHSPELLCHANGED:
case SM_RUSH:
case SM_BACKSTEP:
case SM_NOWDEATH:
case SM_DEATH:
case SM_WALK:
case SM_RUN:
case SM_TURN:
case SM_STRUCK:
case SM_HIT:
case SM_FIREHIT:
case SM_LONGHIT:
case SM_POWERHIT:
case SM_WIDEHIT:
case SM_MAGICFIRE:
case SM_SPELL:

CNPC::UpdatePacketState()
case SM_OPENHEALTH:
case SM_CLOSEHEALTH:
case SM_CHANGELIGHT:
case SM_USERNAME:
case SM_CHANGENAMECOLOR:
case SM_HEALTHSPELLCHANGED:
case SM_TURN:
case SM_HIT:

CActor::UpdatePacketState()
case SM_DEATH: SetMotionFrame(_MT_MON_DIE, bDir);
case SM_WALK: SetMotionFrame(_MT_MON_WALK, bDir);
case SM_TURN: SetMotionFrame(_MT_MON_STAND, bDir);
case SM_DIGUP: SetMotionFrame(_MT_MON_APPEAR, bDir);
case SM_DIGDOWN: SetMotionFrame(_MT_MON_APPEAR, bDir);
case SM_FEATURECHANGED:
case SM_OPENHEALTH:
case SM_CLOSEHEALTH:
case SM_CHANGELIGHT:
case SM_CHANGENAMECOLOR:
case SM_USERNAME:
case SM_HEALTHSPELLCHANGED:
case SM_BACKSTEP: SetMotionFrame(_MT_MON_WALK, bDir);
case SM_STRUCK: SetMotionFrame(_MT_MON_HITTED, m_bCurrDir);
case SM_HIT: SetMotionFrame(_MT_MON_ATTACK_A, bDir);
case SM_FLYAXE:
case SM_LIGHTING:
case SM_SKELETON:

收到多個NPC,玩家發送的SM_TURN消息:由下面對象調用處理:
CHero::OnTurn
CNPC::OnTurn
CActor::OnTurn

根據服務器發送的消息,(創建一個虛擬玩家NPC,怪物,在客戶端),根據參數,初始化該對象設置(方向,坐標,名字,等級等)。在后面的處理中繪制該對象到UI界面中(移動對象的UI界面處理。)

SetMotionFrame(_MT_MON_STAND, bDir); m_bCurrMtn := _MT_MON_STAND
m_dwFstFrame , m_dwEndFrame , m_wDelay 第一幀,最后一幀,延遲時間。

3. AutoTargeting 自動搜索目標(NPC,怪物,玩家等)

4. RenderObject補償對象時間

5. RenderMapTileGrid
m_xMagicList,處理玩家魔法后,UI界面的處理。

6. m_xSnow, m_xRain, m_xFlyingTail, m_xSmoke, m_xLightFog設置場景UI界面處理。

7. m_xMyHero.ShowMessage(nLoopTime); 顯示用戶(UI處理)
m_xMyHero.DrawHPBar(); 顯示用戶HP值。
遍歷m_xActorList,處理所有NPC的UI界面重繪
pxHero->ShowMessage(nLoopTime);
pxHero->DrawHPBar();

8. DropItemShow下拉顯示。

9. 判斷m_pxMouseTargetActor(玩家查看其它玩家,NPC,怪物時)
g_xClientSocket.SendQueryName向服務器提交查詢信息。
m_pxMouseOldTargetActor = m_pxMouseTargetActor; 保存該對象
m_pxMouseTargetActor->DrawName(); 重繪對象名字(UI界面顯示)


下面分析一下用戶登錄之后的流程:
從前面的分析中可以看到,該用戶玩家登錄成功之后,得到了服務器發送來的各種消息。處理也比較復雜,同時有一定的優先級處理。並且根據用戶登錄后的XY坐標,向用戶發送來了服務器XY坐標為中心附近單元格中的所有玩家(NPC,怪物)的SM_TURN消息。
客戶端根據數據包的標志,創建這些NPC,設置屬性,並且把它們加入m_xActorList對列中。最后在UI界面上繪制這些對象。


 

此文章來自網絡,如有版權沖突請和我聯系 512316@qq.com


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM