企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] ## 游戏场景服务器概况 ![sSw1IJ.png](https://s3.ax1x.com/2021/01/02/sSw1IJ.png) >指令对应的处理handle的文件:SSBattleMgr.cpp ## 创建战场 * 指令: eMsgToSSFromCS_CreateBattle * GC服务器发往SS fromCS 收到中心服务器CS创建站场的指令,在函数`INT32 CSSBattleMgr::OnMsgFromCS_CreateBattle(const char* pData, int n32DataLength)`中创建站场成功后,加入到战场管理器中: ``` m_cAllBattleMap[pBattle->GetBattleID()] = pBattle; ``` 发送创建结果给CS服务器 ``` CSSWorkThreadMgr::GetInstance().PostMsgToCS(sMsg, sMsg.mgsid()); ``` 发送可以进入战场的消息给客户端 ``` CSSWorkThreadMgr::GetInstance().PostMsgToGCLIULU((*iter)->GetUserNetInfo(), sMsgBattle, sMsgBattle.msgid()); ``` ## 英雄移动 * 指令:eMsgToGSToSSFromGC_AskMoveDir,eMsgToGSToSSFromGC_AskStopMove * GSToSS: 客户端发往SS,fromGC 收到客户端发来的移动信息, `GCToSS::MoveDir`, 转化为服务器能识别的参数 `CVector3D`, 开始计算客户端移动的位置 ```C++ CVector3D pcDir(pMoveDir->dir().x(), 0, pMoveDir->dir().z()); m_pMsgBattle->AskMoveDir(m_pMsgUser, pcDir); ``` 开始按照方向移动: ```C++ bool CSSMoveMgr::AskStartMoveDir(ISSMoveObject* pMObject, ColVector dir) { ... //计算下一个100毫秒后的位置 pMObject->CalculateStepMoveTarget(now + 100); //检查是否会直接撞墙 if(FALSE == TestNextStepMove(pMObject)){ if(FALSE == TryTurnDir(pMObject)){ pMObject->Stop(now,FALSE); return FALSE; } } pMObject->OnStartMove(pMObject->GetDir()); } ``` ``` INT32 CSSGameUnit::BeginAction_Move(const CVector3D &crsDir, bool bIfNotifyGC){} ``` 同步移动状态到客户端 ``` pcCurBattle->SyncState(this); ... SendMsgToAllWatcher(*sMsg, msgid, pcGO); ... CSSWorkThreadMgr::GetInstance().PostMsgToGCLIULU(watcherArray[i]->GetUserNetInfo(), sMsg, n32MsgID); ``` ``` INT32 CSSBattle::SyncState(CSSGameUnit *pcGO, bool spot){} void CSSBattle::SendMsgToAllWatcher(google::protobuf::Message& sMsg, int n32MsgID, CSSGameUnit* pGU){} ``` ## 英雄技能 * 指令:eMsgToGSToSSFromGC_AskBuyGoods * GSToSS:客户端发往SS,fromGC SS服务器接收到请求释放技能的指令`eMsgToGSToSSFromGC_AskBuyGoods`, 转化数据为`GCToSS::UseSkill`格式 : ``` boost::shared_ptr<GCToSS::UseSkill> pUseSkill = ParseProtoMsgWithNewMemory<GCToSS::UseSkill>(pData, n32DataLength); INT32 nret = m_pMsgBattle->AskUseSkill(m_pMsgUser, pUseSkill->skillid()); ``` 请求释放技能: ``` INT32 CSSAI_Hero::AskUseSkill(UINT32 un32SkillID) {} //检查是否是不能操作状态 //检查是否被沉默了 //检查是否在吸附中,如果是,不能使用技能 //获取并检查技能是否存在 //检查技能是否符合可用条件 //检查是否是正在运行的技能 ``` 开始使用技能 ``` pSkill->Start(); ``` 准备技能的配置 ``` void CSSSkill::MakeSkillEffect(TIME_MILSEC tUTCMilsec){ ... pcCurBattle->GetEffectMgr()->AddEffectsFromCfg((SSNextSkillEffectCfg*)cpsCfg->asSkillModelList, pcMasterGU.get(), pcTarGU.get(), cPos, pcMasterGU->GetCurDir(), this, tUTCMilsec); } ``` 从配置中添加技能 ``` INT32 CSSEffectMgr::AddEffectsFromCfg(SSNextSkillEffectCfg* pEffectCfg, CSSGameUnit* pMaster, CSSGameUnit* pTarget, CVector3D cPos, CVector3D cDir , CSSSkill* pSkill, TIME_MILSEC beginTime, CSSGameUnit* pStartSkillGU){ ... AddEffect(pEffect); } ``` 添加效果到管理器中 ``` INT32 CSSEffectMgr::AddEffect(CSSSkillEffect* pEffect) { ... //尝试使用效果的启动方法。如果启动成功,将其加入正在运行的技能列表中 if(eNormal == pEffect->Begin()){ //if (FALSE == pEffect->m_pCfg->bIsCanMove){ pEffect->AddSelfToUsingList(); //} m_UpdateEffectMap[pEffect->m_un32UniqueID] = pEffect; } //如果效果启动失败,检查其是否会开始计算技能CD,然后结束技能。 else{ pEffect->CheckCooldown(); pEffect->End(); DestroyAFreeSkillEffect(pEffect); return eEC_AddEffectFailed; } ... } //正在运行的效果列表 m_UpdateEffectMap ``` 对应的技能在如下图所示的文件中 ![spS5KH.png](https://s3.ax1x.com/2021/01/02/spS5KH.png) * SSSkillEffect_Buf.cpp: 附加的buff技能 * SSSkillEffect_Fly.cpp: 飞行技能 * ... ## 装备买卖 * 买装备指令:eMsgToGSToSSFromGC_AskBuyGoods * 卖商品指令:eMsgToGSToSSFromGC_AskSellGoods * 释放装备技能:eMsgToGSToSSFromGC_AskUseGoods * GSToSS: 客户端发往SS,fromGC ### 商品配置 目录: * 商品组合:CSBattleMgr/CombineCfg.xml * 商品描述:CSBattleMgr/ItemCfg.xml 商品配置描述: | attributeKeyList / attributeValList | 描述 | | --- | --- | | 5 / 10 | +10 物理攻击 | | 6 / 35 | +35点魔法攻击 | | 7 / 20 | +20 点物理防御 | | 8 / 25 | +25点魔法防御 | | 9 / 60 | +60点移动速度 | | 10 / 200 | +200生命值 | | 11 / 200 | +200生命值 | | 12 / 150 | +150魔法值 | | 13 / 2000 | +2点/秒生命回复 | * `attributeKeyLi`: 占位 * `attributeValList`: 值 * `n32CPCost`: 金币 举例 ``` <info un32GoodsID="30038"> <sNameID>spe_item_HP</sNameID> <sNameCh>神果</sNameCh> <un8TypeID>3</un8TypeID> <attributeKeyList>6</attributeKeyList> <attributeValList>65</attributeValList> <attributePerList>0</attributePerList> <un8UseTimes>0</un8UseTimes> <bDestroyAfterUsed>0</bDestroyAfterUsed> <un32SkillID>0</un32SkillID> <un32PassSkillID>0</un32PassSkillID> <bIsCanDeathToBuy>1</bIsCanDeathToBuy> <bUsedAfterBuyed>0</bUsedAfterBuyed> <sIcon>Dicon038</sIcon> <un32CdTime>0</un32CdTime> <bUniqueID>0</bUniqueID> <un8OverlapTimes>1</un8OverlapTimes> <un8CPCostType>1</un8CPCostType> <n32CPCost>800</n32CPCost> <n32CombineCPCost>200</n32CombineCPCost> <un8FunctionType>0</un8FunctionType> <un32UniqueTypeID>0</un32UniqueTypeID> <sDescribe>+65点魔法攻击</sDescribe> <un32UseSoundID>0</un32UseSoundID> </info> ``` 神果+65点魔法攻击, 售价是800金币。 ## 整个服务器的心跳 心跳的作用: * 检查掉线时间。如果玩家掉线超过30秒,则将其AI替换为机器人AI * 技能心跳 * 移动心跳 * NPC和hero的心跳 ``` void CSSBattle::DoPlayHeartBeat(TIME_MILSEC tUTCMilsec, TIME_TICK tTickSpan){ ... //移动心跳 m_pMoveMgr->OnHeartBeat(tUTCMilsec, tTickSpan); for (GameObjectMap::iterator iterObj = m_cGameObjectMap.begin(); iterObj != m_cGameObjectMap.end(); ++iterObj){ //NPC和hero的心跳 iterObj->second->OnHeartBeat(tUTCMilsec, tTickSpan); } ... //技能心跳 m_pEffectMgr->OnHeartBeat(tUTCMilsec, tTickSpan); m_pPassiveSkillMgr->OnHeartBeat(tUTCMilsec, tTickSpan); m_pSightMgr->OnHeartBeat(tUTCMilsec, tTickSpan); ... } ```