查看完整版本: 传奇源码分析-客户端(游戏逻辑处理源分析三)

51testing 2007-12-13 10:47

传奇源码分析-客户端(游戏逻辑处理源分析三)

[color=black]6. [/color][b][color=black]接收怪物,商人,其它玩家的消息:[/color][/b]
[b][color=black]ProcessUserHuman:([/color][/b][b][color=black]其它玩家—服务器处理)[/color][/b]
[color=black]CPlayerObject->SearchViewRange();[/color]
[color=black]CPlayerObject->Operate();[/color]
遍历UserInfoList列表,依次调用每个UserInfo的Operate来处理命令队列中的所有操作; pUserInfo->Operate()调用m_pxPlayerObject->Operate()调用。根据分发消息(RM_TURN)向客户端发送SM_TURN消息。GameSrv广播新玩家上线(坐标)的消息。向该新玩家发送玩家信息([color=black]等级,装备,魔法,攻击力等)。[/color]
玩家,移动对象:
1. 遍历m_xVisibleObjectList列表,所有(玩家,商人,怪物)发送调用AddProcess
(RM_TURN向周围玩家发送消息)。
地图:
2.遍历m_xVisibleItemList,发送AddProcess(this, RM_ITEMSHOW消息更新地图。
3.遍历m_xVisibleEventList,发送AddProcess(this, RM_SHOWEVENT

[b]ProcessMonster[/b][b]线程[/b]:[b][color=black]([color=black]怪物—服务器处理)[/color][/color][/b]
GameSrv服务器在ProcessMonster线程:[color=black]创建不同的CMonsterObject对象,并且加入xMonsterObjList列表和pMapCellInfo->m_xpObjectList列表中,然后再调用CMonsterObject::SearchViewRange()[/color]更新视线范围内目标,根据g_SearchTable计算出搜索坐标,转换为相应的地图单元格,遍历所有可移动生物,加入m_xVisibleObjectList列表,调用Operate;Operate遍历m_DelayProcessQ列表,过滤出RM_DOOPENHEALTH,RM_STRUCK和RM_MAGSTRUCK三个事件(恢复生命值,攻击,魔法攻击),并处理。
[b]ProcessMerchants[/b][b]线程:(商人--[color=black]服务器处理[/color])[/b]
       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

[b]客户端收到消息后相应的处理:[/b]
1.CGameProcess::OnSocketMessageRecieve加入m_xWaitPacketQueue队列

[b]遍历m_xVisibleObjectList队列中所有移动物体(角色):[/b]
       [b] RM_DISAPPEAR[/b]   消失(SM_DISAPPEAR)  [url=http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ContentPlaceHolder1_EntryEditor1_richTextEditor_richTextEditor&Toolbar=Default#ProcessDefaultPacket函数][color=#0000ff]ProcessDefaultPacket函数[/color][/url]
       [b] RM_DEATH[/b]       死亡(SM_NOWDEATH, SM_DEATH)
           CHero::OnDeath 其它玩家。
           CActor::OnDeath 怪物。
//g_xGameProc.m_xMagicList
        [b]RM_TURN[/b]        移动
[url=http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ContentPlaceHolder1_EntryEditor1_richTextEditor_richTextEditor&Toolbar=Default#SM_TURN消息处理][color=#0000ff]SM_TURN消息处理[/color][/url]

[b]遍历m_xVisibleItemList队列中所有移动物体(地图):[/b]
        [b]RM_ITEMHIDE[/b]    从m_stMapItemList列表中删除该移动对象
[b] RM_ITEMSHOW
[/b] 遍历m_stMapItemList,如果不存在,则创建一个GROUNDITEM结构,并加入m_stMapItemList列表中。
typedef struct tagGROUNDITEM
{
                     INT             nRecog;
                     SHORT           shTileX;
                     SHORT           shTileY;
                     WORD            wLooks;
                     CHAR            szItemName[40];
}GROUNDITEM, *LPGROUNDITEM;

[b]遍历m_xVisibleEventList队列中所有移动物体(事件):[/b]
      [b]  RM_HIDEEVENT   [/b]
[b]RM_SHOWEVENT
[/b]


2. 部分数据未处理,加入m_xWaitPacketQueue队列中由[color=#111111]ProcessPacket[/color][color=#111111]处理。[/color]
CClientSocket::OnSocketMessage的FD_READ事件中,PacketQ.PushQ把接收到的消息,压入PacketQ队列中。处理PacketQ队列数据是由[color=#111111]CGameProcess::Load()[/color][color=#111111]时调用[/color]OnTimer在CGameProcess::OnTimer中处理的,处理过程为:
[color=black]OnTimer -> ProcessPacket -> ProcessPacket[/color][color=black]处理m_xWaitPacketQueue队列消息(OnSocketMessageRecieve函数中未处理的消息)。[/color]

[b][color=black]ProcessPacket [/color][/b][b][color=black]函数处理流程:[/color][/b]
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);
[color=black]判断服务器发送来的消息ID是否相同。m_xMyHero.m_dwIdentity在登录成功的时[/color]
[color=black]候由服务器发送的用户消息获取的。[/color]
[color=black]if ( lpPacketMsg->stDefMsg.nRecog == m_xMyHero.m_dwIdentity )[/color]
[color=black]如果是服务器端游戏玩家自己发送的消息,则处理自己的消息。否则如果是其它玩家(怪物)发送的消息,遍历m_xActorList列表, 判断该对象是否存在,如果该不存在,则根据stFeature.bGender的类型[/color]
[color=black]_GENDER_MAN[/color][color=black]: 创建一个CHero对象,加入到m_xActorList列表中。[/color]
[color=black]_GENDER_WOMAN[/color][color=black]:[/color]
[color=black]_GENDER_NPC[/color][color=black]: 创建一个CNPC对象,加入到m_xActorList列表中。[/color]
[color=black]_GENDER_MON[/color][color=black]: 创建一个CActor对象,加入到m_xActorList列表中。[/color]
[color=black]然后pxActor->m_xPacketQueue.PushQ 然后把消息压入该对象的xPacketQueue列表中。[/color]


[color=black]总结:ProcessPacket处理 [/color]CClientSocket[color=black]类接受的消息(m_xWaitPacketQueue),判断是否是服务器发送给自己的消息,处理一些发送给自己的重要消息,其它消息处理则加入[/color]m_xMyHero.m_xPacketQueue[color=black]队列中,然后再遍历m_xActorList队列,判断如果服务器端发来的消息里的玩家(NPC,怪物),在m_xActorList队列中找不到,就判断一个加入m_xActorList列表中,并且把该消息压入pxActor->m_xPacketQueue交给该NPC去处理该事件。[/color]
[color=black]而xPacketQueue队列的消息分别由该对象的UpdatePacketState处理,如下:[/color]
[color=black]BOOL CActor::UpdatePacketState() ,BOOL CNPC::UpdatePacketState()[/color]
[color=black] BOOL CHero::UpdatePacketState()[/color][color=black]。[/color]

[b][color=#000000]ProcessDefaultPacket[/color][/b][b]函数[b]:[/b][/b]

处理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);销毁该玩家。


[b][color=black]游戏循环处理: [/color][/b][b][color=#111111]CGameProcess::RenderScene(INT nLoopTime)[/color][/b][b][color=#111111]函数:[/color][/b]
[color=#111111]主要流程如下:[/color]
[color=#111111]   wMoveTime += nLoopTime; [/color][color=#111111]判断wMoveTime>100时,bIsMoveTime置为真。[/color]


[color=#111111] 1[/color][color=#111111].m_xMyHero.UpdateMotionState(nLoopTime, bIsMoveTime);处理本玩家消息。[/color]
[color=#111111]     a. UpdatePacketState[/color][color=#111111]函数:[/color]

[color=#111111]遍历m_xPriorPacketQueue队列,如果有[/color]SM_NOWDEATH或SM_DEATH消息,则优先处理。

[color=#111111]处理m_xPacketQueue队列中消息。[/color]
[color=#111111]             SM_STRUCK:[/color]
[color=#111111]             SM_RUSH[/color]
[color=#111111]             SM_BACKSTEP[/color]
[color=#111111]             SM_FEATURECHANGED:[/color]
[color=#111111]             SM_OPENHEALTH:         [/color]
[color=#111111]SM_CLOSEHEALTH:        [/color]
[color=#111111]SM_CHANGELIGHT:        [/color]
[color=#111111]SM_USERNAME:           [/color]
[color=#111111]SM_CHANGENAMECOLOR:[/color]
[color=#111111]             SM_CHARSTATUSCHANGE:   [/color]
[color=#111111]SM_MAGICFIRE:          [/color]
[color=#111111]SM_HEALTHSPELLCHANGED: [/color]

[color=#111111] 2[/color][color=#111111].CheckMappedData函数:遍历m_xActorList列表分别调用[/color]

[color=black]CActor::UpdateMotionState(INT nLoopTime, BOOL bIsMoveTime)[/color]
[color=black]CNPC::UpdateMotionState(INT nLoopTime, BOOL bIsMoveTime)[/color]
[color=black]CMyHero::UpdateMotionState(INT nLoopTime, BOOL bIsMoveTime)[/color]

[color=black]处理自己消息。[/color]

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


[color=black] CNPC::UpdatePacketState()[/color]
[color=black]     case SM_OPENHEALTH:            [/color]
[color=black]      case SM_CLOSEHEALTH:   [/color]
[color=black]      case SM_CHANGELIGHT:       [/color]
[color=black]      case SM_USERNAME:          [/color]
[color=black]      case SM_CHANGENAMECOLOR:   [/color]
[color=black]      case SM_HEALTHSPELLCHANGED:    [/color]
[color=black]      case SM_TURN:              [/color]
[color=black]      case SM_HIT:[/color]

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


[color=black]收到多个NPC,玩家发送的SM_TURN消息:由下面对象调用处理:[/color]
[color=black]CHero::OnTurn[/color]
[color=black]CNPC::OnTurn[/color]
[color=black]CActor::OnTurn[/color]

[color=black]根据服务器发送的消息,(创建一个虚拟玩家NPC,怪物,在客户端),根据参数,初始化该对象设置(方向,坐标,名字,等级等)。在后面的处理中绘制该对象到UI界面中([url=http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ContentPlaceHolder1_EntryEditor1_richTextEditor_richTextEditor&Toolbar=Default#移动对象的UI界面处理][color=#0000ff]移动对象的UI界面处理。[/color][/url])[/color]


[color=black]        SetMotionFrame(_MT_MON_STAND, bDir); m_bCurrMtn := _MT_MON_STAND[/color]
[color=black]        m_dwFstFrame , m_dwEndFrame , m_wDelay [/color][color=black]第一帧,最后一帧,延迟时间。[/color]

[color=black]   3.  AutoTargeting [/color][color=black]自动搜索目标(NPC,怪物,玩家等)[/color]


[color=black]   4[/color][color=black]. RenderObject补偿对象时间[/color]


[color=black]   5.  RenderMapTileGrid[/color]
[color=black]       m_xMagicList[/color][color=black],处理玩家魔法后,UI界面的处理。[/color]

[color=black]6.
[/color][color=black]m_xSnow, m_xRain, m_xFlyingTail, m_xSmoke, m_xLightFog[/color][color=black]设置场景UI界面处理。[/color]

[color=black]  [color=#000000]7.[/color][/color] [color=black]m_xMyHero.ShowMessage(nLoopTime); [/color][color=black]显示用户(UI处理)[/color]
[color=black] m_xMyHero.DrawHPBar(); [/color][color=black]显示用户HP值。[/color]

[color=black]遍历m_xActorList,处理所有NPC的UI界面重绘[/color]
[color=black]   pxHero->ShowMessage(nLoopTime);[/color]
[color=black] pxHero->DrawHPBar();[/color]


[color=black] 8.[/color] [color=black]DropItemShow[/color][color=black]下拉显示。[/color]

[color=black]9.[/color] 判断[color=black]m_pxMouseTargetActor([color=black]玩家查看其它玩家,NPC,怪物时)[/color][/color]
[color=black]   g_xClientSocket.SendQueryName[/color][color=black]向服务器提交查询信息。[/color]
[color=#111111]m_pxMouseOldTargetActor = m_pxMouseTargetActor; [/color][color=#111111]保存该对象[/color]
[color=#111111]     m_pxMouseTargetActor->DrawName(); [/color][color=#111111]重绘对象名字(UI界面显示)[/color]


下面分析一下用户登录之后的流程:
从前面的分析中可以看到,该用户玩家登录成功之后,得到了服务器发送来的各种消息。处理也比较复杂,同时有一定的优先级处理。并且根据用户登录后的XY坐标,向用户发送来了服务器XY坐标为中心附近单元格中的所有玩家(NPC,怪物)的[color=black]SM_TURN[/color][color=black]消息。[/color]
[color=black]客户端根据数据包的标志,创建这些NPC,设置属性,并且把它们加入m_xActorList对列中。最后在UI界面上绘制这些对象。[/color]
页: [1]
查看完整版本: 传奇源码分析-客户端(游戏逻辑处理源分析三)