/** * @file Player.cpp * @brief 定义玩家类 * Copyright(c) 2007,上海第九城市游戏研发部 * All rights reserved * 文件名称: Player.cpp * 摘 要: 定义玩家类; * 作 者: dzj * 完成日期: 2007.11.29 * */ #include "Player.h" #include "../OtherServer/otherserver.h" #include "../mapteleport/MapTeleporterManager.h" #include unsigned int CPlayer::g_uniPlayerID = RAND % 10000000; using namespace MUX_PROTO; #ifdef DS_EPOLL bool CPlayer::m_bIsIssueKickAllPlayer = false;//发起断开所有玩家; CManFrame* CManPlayer::m_pManFrame = NULL; #else //DS_EPOLL #ifdef USE_SELF_HASH DsHashTable< HashTbPtrEle, 3000, 2 >* CManPlayer::m_pHashPlayers; #else //USE_SELF_HASH map CManPlayer::m_mapPlayers;//所有其它srv; #endif //USE_SELF_HASH #endif //DS_EPOLL #ifdef DS_EPOLL //以下DS_EPOLL框架需要的定义 ///获得一个自身的对象实例,与DestorySelfIns对应; CPlayer* CPlayer::CreateSelfIns() { CPlayer* pTmpTestPlayer = g_TestPlayerPool->DsRetrieve( TestPlayerNO ); if ( NULL == pTmpTestPlayer ) { return NULL; } pTmpTestPlayer->OnFrameEleCreated(); return pTmpTestPlayer; } ///释放自身,与CreateSelfIns对应; void CPlayer::DestorySelfIns() { NewLog( LOG_LEV_INFO, "CPlayer::DestorySelfIns,删除自身" ); OnDestoryed();//调用原来代码的断开处理; OnFrameEleDestoryed(); g_TestPlayerPool->DsRelease( TestPlayerNO, this ); }; #endif //DS_EPOLL void NetDetectInfo::SendOneNewPkg() { PLAYER_STAT curstat = m_pPlayer->GetCurStat(); if ( ( curstat < PS_DB_LOGIN_QUERYING ) || ( curstat > PS_DETAIL_INFO_GOT ) ) { /* PS_DB_LOGIN_QUERYING, //查询DB玩家信息中 PS_DB_LOGIN_QUERYED, //DB玩家信息已返回 PS_ROLESELED, //角色已选 PS_QUERY_DETAIL_INFO, //向DB请求玩家所选角色详细信息; PS_DETAIL_INFO_GOT, //DB已返回玩家所选角色详细信息; */ //未进入对时窗口; return; } if ( m_bIsBiasAquired ) { //已对时,不再发新的对时包; return; } if ( (int)(m_vecNetDetectPkgSendTime.size()) >= MAX_DETECT_NUM ) { //超过了检测次数限制,不再发新的对时包; return; } GCNetDetect netDetect; netDetect.pkgID = (int)(m_vecNetDetectPkgSendTime.size()); NewSendPlayerPkg( GCNetDetect, m_pPlayer, netDetect ); m_vecNetDetectPkgSendTime.push_back( ACE_OS::gettimeofday() ); m_vecNetDetectPkgDateTime.push_back( time(NULL) ); return; } void NetDetectInfo::NetDetectPkgRcved( int pkgID) { if ( m_bIsBiasAquired ) { //已经对好时了,不再重复对; return; } if ( ( pkgID<0 ) || ( pkgID>=(int)(m_vecNetDetectPkgSendTime.size()) ) ) { //不可能的ID号; D_ERROR( "NetDetectInfo::NetDetectPkgRcved收到不可能的包编号%d", pkgID ); return; } ++ m_nRcvedNum; if ( m_nRcvedNum>MAX_DETECT_NUM ) { D_ERROR( "NetDetectInfo::NetDetectPkgRcved中m_nRcvedNum>MAX_DETECT_NUM\n" ); return; } ACE_Time_Value passedTime = ACE_OS::gettimeofday() - m_vecNetDetectPkgSendTime[pkgID]; if ( m_nMinDelay > (int)(passedTime.msec()) ) { m_nMinDelay = passedTime.msec();//目前为止的最小延迟; m_nMinDelayPkgID = pkgID; ACE_Time_Value tmpValue = ACE_Time_Value::zero; tmpValue.msec( passedTime.msec() / 2 ); m_timeBias = m_vecNetDetectPkgSendTime[pkgID] + tmpValue;//如果网络包来回延迟小于等于预定阈值,则以对应网络包的发出时刻+延迟/2作为与该客户端通信的时间基准; } if ( m_nMinDelay <= DETECT_BIAS ) { m_bIsBiasAquired = true; GCNetBias netBias; netBias.pkgID = m_nMinDelayPkgID; if ( (unsigned int)m_nMinDelayPkgID >= m_vecNetDetectPkgDateTime.size() ) { D_ERROR( "NetDetectInfo::NetDetectPkgRcved, m_nMinDelay <= DETECT_BIAS, m_nMinDelayPkgID(%d) >= m_vecNetDetectPkgDateTime.size()\n", m_nMinDelayPkgID ); return; } netBias.BiasTime = (TYPE_TIME)m_vecNetDetectPkgDateTime[m_nMinDelayPkgID]; NewSendPlayerPkg( GCNetBias, m_pPlayer, netBias );//发送时间基准确定包; D_DEBUG("time:===%d now:%d \n", netBias.BiasTime, time(NULL) ); } else { //如果检测包数超过预定限制,则选一个最小延迟者作为对时基准; if ( pkgID >= MAX_DETECT_NUM ) { D_WARNING( "玩家%s最后确定时间基准的包延迟%d过大", m_pPlayer->GetAccount(), m_nMinDelay ); m_bIsBiasAquired = true; GCNetBias netBias; netBias.pkgID = m_nMinDelayPkgID; if ( (unsigned int)m_nMinDelayPkgID >= m_vecNetDetectPkgDateTime.size() ) { D_ERROR( "NetDetectInfo::NetDetectPkgRcved, pkgID >= MAX_DETECT_NUM, m_nMinDelayPkgID(%d) >= m_vecNetDetectPkgDateTime.size()\n", m_nMinDelayPkgID ); return; } netBias.BiasTime = (TYPE_TIME)m_vecNetDetectPkgDateTime[m_nMinDelayPkgID]; NewSendPlayerPkg( GCNetBias, m_pPlayer, netBias );//发送时间基准确定包; } } return; } void OnDealPkgNoRegCmd( CPlayer* pPlayer, unsigned short wCmd ) { if ( NULL == pPlayer ) { D_ERROR( "OnDealPkgNoRegCmd, 玩家指针空\n" ); return; } D_ERROR( "玩家%s(%d)发来未注册命令%x,踢其下线\n", pPlayer->GetAccount(), pPlayer->GetPlayerID().dwPID, wCmd ); //todo wcj 2010.12.29 暂时屏蔽 pPlayer->ReqDestorySelf(); return; } void CPlayer::OnNetDetectPkgRcved( int pkgID ) { return m_NetDetectInfo.NetDetectPkgRcved( pkgID ); } ///向客户端发送网络延时检测包; void CPlayer::SendNetDetectPkg() { if ( IsTimeBiasAquired() ) { return; } return m_NetDetectInfo.SendOneNewPkg(); } ///置玩家的句柄信息,每次新建时必须调用; void CPlayer::SetHandleInfo( int nHandleID, int nSessionID ) { TRY_BEGIN; m_bIsDesSelf = false; if ( nSessionID <=SRV_SID_MAX ) { //连其它srv成功; D_WARNING( "错误的nSessionID:%d, 玩家的sessionID应该大于SRV_SID_MAX:%d\n", nSessionID, SRV_SID_MAX ); //D_WARNING( "mapserver连接成功:%d\n\n", nSessionID ); } StructMemSet( m_strAccount, 0, sizeof(m_strAccount) );//初始帐号与密码清0; StructMemSet( m_strPwd, 0, sizeof(m_strPwd) ); m_nHandleID = nHandleID; m_nSessionID = nSessionID; SetCurStat( PS_CONN ); SetBeatRcved();//初始化上次心跳包收到时刻; #ifndef DS_EPOLL CManPlayer::AddOnePlayer( this ); #endif //DS_EPOLL if ( nSessionID > SRV_SID_MAX ) { //m_pDealPkg = new CDealPlayerPkg; //D_WARNING( "有新的客户端连入:%d\n", nSessionID ); //普通玩家上线; } return; TRY_END; return; } ///保存gate上的fullplayerinfo至DB; bool CPlayer::SaveFullInfoToDB( bool isOffline ) { TRY_BEGIN; CDbSrv* pDbSrv = CManDbSrvs::GetDbsrvByAccount( GetAccount() ); if ( NULL == pDbSrv ) { D_ERROR( "MapSrv发来玩家的信息更新时,找不到对应的DbSrv,严重错误!\n" ); NoDBPlayerInfoBackup( GetAccount(), m_fullPlayerInfo ); return false; } //副本处理:若玩家当前在副本中,则保存玩家的副本外地图位置,而不是副本中位置; // 本来mapsrv也会做类似处理,但如果是NOT_EXIST gate下线,则本gate不会再等待mapsrv的fullinfo,而只会以当前gate的信息存DB; unsigned short usmapid = m_fullPlayerInfo.baseInfo.usMapID; unsigned short iposx = m_fullPlayerInfo.baseInfo.iPosX; unsigned short iposy = m_fullPlayerInfo.baseInfo.iPosY; if ( m_outMapInfo.isOutMapInfoSet ) { D_DEBUG( "玩家已进副本,存DB时存其副本外位置\n" ); m_fullPlayerInfo.baseInfo.usMapID = m_outMapInfo.usMapID; m_fullPlayerInfo.baseInfo.iPosX = m_outMapInfo.iPosX; m_fullPlayerInfo.baseInfo.iPosY = m_outMapInfo.iPosY; } D_DEBUG( "CPlayer::SaveFullInfoToDB,保存玩家%s:%d(%d,%d)信息至DB\n" , m_fullPlayerInfo.baseInfo.szAccount, m_fullPlayerInfo.baseInfo.usMapID, m_fullPlayerInfo.baseInfo.iPosX, m_fullPlayerInfo.baseInfo.iPosY ); std::vector vec; SendFullStr( &m_fullPlayerInfo, vec ); for( std::vector::iterator i = vec.begin(); vec.end() != i; ++i ) { i->playerID = GetPlayerID(); i->uiRoleID = m_fullPlayerInfo.baseInfo.uiID;//如果无此信息,则DB无法更新数据库; i->isOffline = isOffline;//因为下线消息已经另行处理了; //MsgToPut* pNewMsg = CreateSrvPkg( GDUpdatePlayerInfo, pDbSrv, *i ); //pDbSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GDUpdatePlayerInfo, pDbSrv, *i ); } //对应上述的副本处理,只是存DB数据改变,因为如果不是下线,则玩家在副本中位置仍然有用,所以需要恢复; if ( !isOffline ) { m_fullPlayerInfo.baseInfo.usMapID = usmapid; m_fullPlayerInfo.baseInfo.iPosX = iposx; m_fullPlayerInfo.baseInfo.iPosY = iposy; } return true; TRY_END; return false; } ///无DB时,备份玩家存盘信息以便稍后恢复; bool NoDBPlayerInfoBackup( const char* playerAccount, const FullPlayerInfo& fullPlayerInfo ) { TRY_BEGIN; static unsigned int backID = 0; ++backID; D_ERROR( "NoDBPlayerInfoBackup,Player:%s,ID:%d\n", playerAccount, backID ); stringstream filename(""); filename << playerAccount << "_" << backID << ".dat"; FILE* backFile = NULL; #ifdef ACE_WIN32 errno_t errval = fopen_s( &backFile, filename.str().c_str(), "wb" ); if ( 0!= errval ) #else //ACE_WIN32 backFile = fopen( filename.str().c_str(), "wb" ); if ( NULL == backFile ) #endif //ACE_WIN32 { D_ERROR( "!!!,NoDBPlayerInfoBackup,创建玩家信息备份文件%s失败\n", filename.str().c_str() ); return false; } size_t writelen = fwrite( (void*)&fullPlayerInfo, sizeof(fullPlayerInfo), 1, backFile ); if ( writelen <=0 ) { D_ERROR( "!!!,NoDBPlayerInfoBackup,写玩家信息备份文件%s失败\n", filename.str().c_str() ); fclose( backFile ); return false; } fclose( backFile ); return true; TRY_END; return false; } ///恢复之前备份的玩家存盘信息; bool NoDBPlayerInfoRestore( const char* backFileName ) { TRY_BEGIN; D_DEBUG( "NoDBPlayerInfoRestore,backFileName:%s\n", backFileName ); FullPlayerInfo fullPlayerInfo;//用于存放读取到的玩家信息 FILE* backFile = NULL; #ifdef ACE_WIN32 errno_t errval = fopen_s( &backFile, backFileName, "rb" ); if ( 0!= errval ) #else //ACE_WIN32 backFile = fopen( backFileName, "rb" ); if ( NULL == backFile ) #endif //ACE_WIN32 { D_ERROR( "!!!,NoDBPlayerInfoRestore,打开玩家信息备份文件%s失败\n", backFileName ); return false; } size_t writelen = fread( (void*)&fullPlayerInfo, sizeof(fullPlayerInfo), 1, backFile ); if ( writelen <=0 ) { D_ERROR( "!!!,NoDBPlayerInfoRestore,读玩家信息备份文件%s失败\n", backFileName ); fclose( backFile ); return false; } fclose( backFile ); CDbSrv* pDbSrv = CManDbSrvs::GetDbsrvByAccount( fullPlayerInfo.baseInfo.szAccount ); if ( NULL == pDbSrv ) { D_ERROR( "!!!,NoDBPlayerInfoRestore,找不到对应的DbSrv!\n" ); return false; } std::vector vec; SendFullStr( &fullPlayerInfo, vec ); for(std::vector::iterator i = vec.begin(); vec.end() != i; i++) { i->playerID.wGID = 0; i->playerID.dwPID = 0; i->uiRoleID = fullPlayerInfo.baseInfo.uiID;//如果无此信息,则DB无法更新数据库; i->isOffline = true; //MsgToPut* pNewMsg = CreateSrvPkg( GDUpdatePlayerInfo, pDbSrv, *i ); //pDbSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GDUpdatePlayerInfo, pDbSrv, *i ); } D_DEBUG( "NoDBPlayerInfoRestore,保存玩家:%s(%s)(%d:%d,%d)信息至DB,恢复数据成功\n" , fullPlayerInfo.baseInfo.szAccount, fullPlayerInfo.baseInfo.szNickName , fullPlayerInfo.baseInfo.usMapID, fullPlayerInfo.baseInfo.iPosX, fullPlayerInfo.baseInfo.iPosY ); return true; TRY_END; return false; } ///销毁时的处理(连接断开) ///注意:在新建连接之前也会调用这里; void CPlayer::OnDestoryed() { TRY_BEGIN; #ifdef USE_DSIOCP if ( NULL != m_pUniqueSocket ) { if ( NULL != g_poolUniDssocket ) { if ( NULL != g_poolUniDssocket ) { g_poolUniDssocket->Release( m_pUniqueSocket ); m_pUniqueSocket = NULL; } } } #endif //USE_DSIOCP // CheckPosInfoRestore();//检查是否有必要恢复玩家的位置信息(例如:跳副本中途玩家下线时就需要) CMapSrv* pMapSrv = NULL; //集中放在goto之前以防止centos下编译器的检查错误; MsgToPut* pNewMsg = NULL; CCenterSrv* pCenterSrv = NULL; CNewLoginSrv* pNewLoginSrv = NULL; GMPlayerLeave leaveGMMsg; int situation = 1;//第一种情形; #ifndef DS_EPOLL //新dspoll实现不会在新建连接时调用本函数,只会在真正断开时调用 if ( 0 == m_nHandleID ) { //新建连接,跳过断连处理; goto DISCONNECT_PROC_END; } //确实为断开,区别于新建连接时的回调; //以下断开处理; CManPlayer::RemovePlayer( this ); #endif //DS_EPOLL /* //如果已经进入了MapSrv, //则玩家下线时MapSrv会保存玩家最新信息, //只有保存过后才能让新的玩家登录以防止复制装备之类的事件发生, //也只能在保存过玩家新信息后才能通知centersrv玩家已下线, //因此,这里暂时不通知centersrv */ if ( m_nSessionID <= SRV_SID_MAX ) { D_WARNING( "断线玩家的sessionID%d小于等于SRV_SID_MAX\n", m_nHandleID ); goto DISCONNECT_PROC_END; }//如断线ID不是正常玩家ID; /********************************************************************\ * * hym暂时关掉 防沉迷系统 * \********************************************************************/ /* //通知loginserver(防沉迷计时结束) pNewLoginSrv = CManNewLoginSrv::GetNewLoginSrv(); if ( NULL == pNewLoginSrv ) { //找不到登录服务器; D_WARNING( "玩家%d下线,找不到新登录服务器\n\n", m_nSessionID ); goto DISCONNECT_PROC_END; } */ GL_ReportUserLeaveGame leaveGameNotify; leaveGameNotify.gateId = GetPlayerID().wGID; leaveGameNotify.playerId = GetPlayerID().dwPID; SafeStrCpy( leaveGameNotify.userId.userId, GetAccount() ); leaveGameNotify.userId.userIdLen = (unsigned short) (strlen( leaveGameNotify.userId.userId ) + 1); //pNewMsg = CreateNewLoginSrvPkg( GL_ReportUserLeaveGame, pNewLoginSrv, leaveGameNotify ); //pNewLoginSrv->SendPkgToSrv( pNewMsg );//通知loginsrv玩家离开; SendMsgToNewLoginSrv( GL_ReportUserLeaveGame, leaveGameNotify ); //以下玩家断线处理; pCenterSrv = CManCenterSrvs::GetCenterserver(); if ( NULL == pCenterSrv ) { D_ERROR( "玩家%d下线时,找不到centersrv\n", m_nSessionID ); goto DISCONNECT_PROC_END; }//如无center; D_WARNING_DAY( "socketID:%d下线,其当前状态%d,当前gatesrv人数%d\n", m_nSessionID, GetCurStat(), CManPlayer::GetPlayerNum() ); if ( ( GetCurStat() >= PS_CENTER_CHECKING ) && IsIrcPlayer() ) { //已验证过的IRC玩家直接通知centersrv下线; GEPlayerOffline playerOffline; playerOffline.playerID = GetPlayerID(); SafeStrCpy( playerOffline.szAccount, GetAccount() ); //pNewMsg = CreateSrvPkg( GEPlayerOffline, pCenterSrv, playerOffline ); //pCenterSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GEPlayerOffline, pCenterSrv, playerOffline ); D_DEBUG( "5、通知centersrv,%s下线\n", playerOffline.szAccount ); CLogManager::DoAccountLogout(this, 0);//记录下线 OnUpdateSelfInfo( true ); goto DISCONNECT_PROC_END; }//如为已经过center验证的IRC玩家; //以下正常玩家处理; if ( GetCurStat() < PS_CENTER_CHECKING ) { //未经过登录验证,也就还未通知center,因此无需通知center该玩家的下线事件; goto DISCONNECT_PROC_END; }//如还未经过center验证; if ( ( GetCurStat() >= PS_CENTER_CHECKING ) && ( GetCurStat() < PS_DB_PRE ) //通知过center,且还未向map发过DbPre,直接通知centersrv玩家下线; ) { //D_DEBUG( "通知centersrv,socketID:%d下线\n", m_nSessionID ); //已经发过了centersrv检测请求,则通知centersrv该玩家下线; GEPlayerOffline playerOffline; playerOffline.playerID = GetPlayerID(); SafeStrCpy( playerOffline.szAccount, GetAccount() ); //pNewMsg = CreateSrvPkg( GEPlayerOffline, pCenterSrv, playerOffline ); //pCenterSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GEPlayerOffline, pCenterSrv, playerOffline ); D_DEBUG( "6、通知centersrv,%s下线\n", playerOffline.szAccount ); CLogManager::DoAccountLogout(this, 0);//记录下线 goto DISCONNECT_PROC_END; } //如经过了centersrv验证,但还未向map发过DbPre; //关于组队的判断 if( IsInTeam() ) { RemoveTeamMemberRequest req; req.palyerId = GetPlayerID().dwPID; req.gateId = GetPlayerID().wGID; req.removedMode = 0; req.requestSeq = 0; req.teamInd = m_TeamInfo.GetTeamId(); CRelationSrv* pSrv = CManRelationSrvs::GetRelationserver(); if( NULL != pSrv ) { //pNewMsg = CreateRelationPkg( RemoveTeamMemberRequest, pSrv, req ); //pSrv->SendPkgToSrv( pNewMsg ); SendMsgToRelationSrv( RemoveTeamMemberRequest, req ); D_DEBUG("组队退出发送移除请求 退出人:%s\n", GetRoleName() ); } else { D_ERROR("CPlayer::OnDestoryed, 在组队中,找不到relationSrv\n"); //return; } } OnUpdateSelfInfo( true ); if ( IsInSwitching() //跳地图中,区别处理,或者等map消息,或者直接通知center; && ( IsSwitchOrgMapSrvLeft() ) ) { /* 无论有没有收到玩家的准备好消息,如果没收到原地图正常离开消息,则不直接通知centersrv,等原mapsrv发来跳地图更新消息后通知centersrv; 如果已收到原地图正常离开消息,则直接通知centersrv下线,同时通知dbsrv,因为正常离开原地图时还没保存过信息。 */ //已经收到过原mapsrv的离开消息,那就不必等mapsrv了,直接通知centersrv; D_ERROR( "玩家%s跳地图过程中下线,通知centersrv,socketID:%d下线\n", GetAccount(), m_nSessionID ); SaveFullInfoToDB( true );//并保存full信息至DB; //已经发过了centersrv检测请求,则通知centersrv该玩家下线; GEPlayerOffline playerOffline; playerOffline.playerID = GetPlayerID(); SafeStrCpy( playerOffline.szAccount, GetAccount() ); //pNewMsg = CreateSrvPkg( GEPlayerOffline, pCenterSrv, playerOffline ); //pCenterSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GEPlayerOffline, pCenterSrv, playerOffline ); D_DEBUG( "7、通知centersrv,%s下线\n", playerOffline.szAccount ); CLogManager::DoAccountLogout(this, 0);//记录下线 goto DISCONNECT_PROC_END; } //如跳地图中; //非IRC玩家,不是跳地图(或跳地图,但未收到原地图离开消息),在DB_PRE之后 if ( IsInSwitching() ) { //等待mapsrv发来的下线fullinfo; //跳地图中,未收到原地图离开消息时玩家断开 D_WARNING( "跳地图中,未收到原地图离开消息时玩家断开,%s,继续等待\n", GetAccount() ); goto DISCONNECT_PROC_END; } //D_DEBUG( "准备通知mapsrv,socketID:%d下线\n", m_nSessionID ); pMapSrv = GetMapSrv(); if ( NULL == pMapSrv ) { D_ERROR( "socketID:%d断开,DB_PRE之后找不到MapSrv,直接通知centersrv\n", m_nSessionID ); //此时的信息已不准确,不能保存,只能回档查日志,直接通知centersrv下线,这样mapsrv恢复正常后玩家才能继续上线,在线计时之类也才能正确; //SaveFullInfoToDB( true );//并保存full信息至DB; //已经发过了centersrv检测请求,则通知centersrv该玩家下线; GEPlayerOffline playerOffline; playerOffline.playerID = GetPlayerID(); SafeStrCpy( playerOffline.szAccount, GetAccount() ); //pNewMsg = CreateSrvPkg( GEPlayerOffline, pCenterSrv, playerOffline ); //pCenterSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GEPlayerOffline, pCenterSrv, playerOffline ); D_DEBUG( "8、通知centersrv,%s下线\n", playerOffline.szAccount ); CLogManager::DoAccountLogout(this, 0);//记录下线 goto DISCONNECT_PROC_END; } if ( !m_bIsLeaveNotiMapSrv ) { ///mapsrv此玩家已不存在,直接通知centersrv此玩家下线; D_ERROR( "socketID:%d断开,DB_PRE之后,但玩家%s之前已不存在于mapsrv,因此直接通知centersrv\n", m_nSessionID, GetAccount() ); //此时的信息已不准确,不能保存,只能回档查日志,直接通知centersrv下线,这样mapsrv恢复正常后玩家才能继续上线,在线计时之类也才能正确; //SaveFullInfoToDB( true );//并保存full信息至DB; //已经发过了centersrv检测请求,则通知centersrv该玩家下线; GEPlayerOffline playerOffline; playerOffline.playerID = GetPlayerID(); SafeStrCpy( playerOffline.szAccount, GetAccount() ); //pNewMsg = CreateSrvPkg( GEPlayerOffline, pCenterSrv, playerOffline ); //pCenterSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GEPlayerOffline, pCenterSrv, playerOffline ); D_DEBUG( "10、通知centersrv,%s下线\n", playerOffline.szAccount ); CLogManager::DoAccountLogout(this, 0);//记录下线 goto DISCONNECT_PROC_END; } //以下无论如何都通知map, // 区别在于:第一种情形:如果是已进入MAPFIGHTING,则通知消息中无特殊标记,同时不直接通知centersrv,而是等mapsrv的离开消息到来后,更新DB,并通知centersrv; // 第二种情形:否则,通知mapsrv中置特别标记,表明gate已直接通知centersrv而不等待mapsrv消息且无需更新DB信息,mapsrv收到后直接删去此玩家, // 在第二种情形可能是由于gate刚向mapsrv发进入请求玩家就断线,现在这种处理办法存在一点漏洞,即:玩家在mapsrv已出现,且属性有了一些变化,但这些 // 变化信息将由于现在的处理办法而无法得到正确保存; if ( GetCurStat() == PS_MAPFIGHTING ) { D_DEBUG( "通知mapsrv,socketID:%d下线,一般正常情形1,等待mapsrv发来的下线消息。。。\n", m_nSessionID ); situation = 1;//第一种情形; } else { D_WARNING( "通知mapsrv,socketID:%d下线,特殊情形2(进地图过程中下线)\n", m_nSessionID ); SaveFullInfoToDB( true );//并保存full信息至DB; situation = 2;//第二种情形; } //已经发过了mapsrv进入请求,则通知mapsrv该玩家下线; leaveGMMsg.lPlayerID = GetPlayerID(); leaveGMMsg.lMapCode = GetMapID(); if ( 1 == situation ) { leaveGMMsg.nSpecialFlag = GMPlayerLeave::NO_SPECIAL;//无特殊标记; } else { leaveGMMsg.nSpecialFlag = GMPlayerLeave::NOT_EXIST;//gatesrv直接删去并通知DB; } //pNewMsg = CreateSrvPkg( GMPlayerLeave, pMapSrv, leaveGMMsg ); //pMapSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMPlayerLeave, pMapSrv, leaveGMMsg ); D_DEBUG( "通知mapsrv%d,玩家%s离线\n", GetMapSrvID(), GetAccount() ); //如果是PS_MAPFIGHTING,则不会通知centersrv,而会等mapsrv存盘消息来后再通知centersrv //组队只可能是在PS_MAPFIGHTING和PS_SWITCHING中,PS_SWITCHING已在上面做过判定,所以此处不用再通知RelationSrv 8.11 if ( 2==situation ) { //如果不是在地图战斗中,则通知map的同时,直接通知centersrv下线; GEPlayerOffline playerOffline; playerOffline.playerID = GetPlayerID(); SafeStrCpy( playerOffline.szAccount, GetAccount() ); //pNewMsg = CreateSrvPkg( GEPlayerOffline, pCenterSrv, playerOffline ); //pCenterSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GEPlayerOffline, pCenterSrv, playerOffline ); D_DEBUG( "9、通知centersrv,%s下线\n", playerOffline.szAccount ); CLogManager::DoAccountLogout(this, 0);//记录下线 } SetCurStat( PS_INVALID ); DISCONNECT_PROC_END: #ifndef DS_EPOLL ResetInfo(); IncUID();//保证每次销毁之前都递增唯一ID号; #endif //DS_EPOLL return; TRY_END; return; } //收包处理; #ifdef DS_EPOLL bool CPlayer::OnPkgRcved( unsigned int timeInfo, unsigned short wCmd, const char* pPkg, unsigned short wPkgLen ) #else //DS_EPOLL bool CPlayer::OnPkgRcved( unsigned short wCmd, const char* pPkg, unsigned short wPkgLen ) #endif //DS_EPOLL { ST_SIG_CATCH { //TRY_BEGIN; #ifdef DS_EPOLL if ( !IsPlayerRobot() )//只对非机器人进行变速检测,因为机器人没有填写时间信息; { unsigned int srvTicks = m_NetDetectInfo.GetClientPassedTime(); bool isAbnormal = false;//是否变速; if ( srvTicks > 3000 ) //对时完成已超过3秒(客户端收到对时基准包,并使用此基准开始发包的最大时间容许),开始变速检测 { if ( srvTicks > timeInfo ) { //正常情形,服务器ticks略大于客户端,但不能超过很多; //NewLog( LOG_LEV_DEBUG, "客户端%s与服务器端时间差,正%d", GetAccount(), srvTicks-timeInfo ); if ( srvTicks - timeInfo > 5000 ) { //时差超过5秒 NewLog( LOG_LEV_WARNING, "客户端%s减速,准备断开之", GetAccount() ); isAbnormal = true; } } else { //不太正常,客户端ticks大于服务器,除非网络延迟接近0,即便如此,两边也不应相差太多; //NewLog( LOG_LEV_DEBUG, "客户端%s与服务器端时间差,负%d", GetAccount(), timeInfo-srvTicks ); if ( timeInfo - srvTicks > 3000 ) { NewLog( LOG_LEV_WARNING, "客户端%s加速,准备断开之", GetAccount() ); isAbnormal = true; } } } if ( isAbnormal ) { ReqDestorySelf(); return false; } } #endif //DS_EPOLL CDealPlayerPkg::DealPkg( this, wCmd, pPkg, wPkgLen ); RECV_FROM_CLI_STAT( wCmd, wPkgLen ); //return true; //TRY_END; //return false; } END_SIG_CATCH; return true; }; //通知玩家排行榜信息时,同时告知其自身的相关值 bool CPlayer::FillSelfRankInfo( GCNewRankInfo& rankInfo ) { ERankType rankType = rankInfo.rankType;//排行榜类型; switch (rankType) { case RANK_DAMAGE: rankInfo.selfVal = m_fullPlayerInfo.stateInfo.GetMaxOutDamage( m_fullPlayerInfo.stateInfo.GetMaxOutDamageSeq() ); break; case RANK_KILL: rankInfo.selfVal = m_fullPlayerInfo.stateInfo.GetKillTimes( m_fullPlayerInfo.stateInfo.GetKillTimesSeq() ); break; case RANK_BEKILL: rankInfo.selfVal = m_fullPlayerInfo.stateInfo.GetBeKillTimes( m_fullPlayerInfo.stateInfo.GetBeKillTimesSeq() ); break; default: { return false; } } return true; } //本玩家对应的mapsrv指针,注意!!!,永远不要直接使用本指针,而要通过GetMapSrv来获取,否则会有指针悬挂问题; CMapSrv* CPlayer::GetMapSrv() { return CManMapSrvs::GetMapserver( GetMapSrvID() ); } ///跳地图状态中,玩家发进入目标地图消息 void CPlayer::SwitchPlayerEnterNewMap( TYPE_ID sequenceID ) { ACE_UNUSED_ARG( sequenceID ); if ( !IsInSwitching() ) { D_ERROR( "收到玩家跳地图进入新地图消息时,玩家不处于跳地图状态" ); return; } m_SwitchMapStat.PlayerSwitchReady(); if ( m_SwitchMapStat.IsEnterNewMapSrv() ) { //发进入新mapsrv请求; EnterMapSrv( false );//跳地图不进行排队检测,因为跳地图之前会先根据之前数据估计目标地图人数,如果人太多,根本不发起跳地图。 } } //设置玩家在GateSrv中保存的骑乘信息 void CPlayer::SetRideState( ERIDESTATE eState ,int attachInfo1,int attachInfo2 ) { if ( eState != E_RIDE_INFO_UPDATE ) m_rideTeamInfo.SetRideState( eState ); m_rideTeamInfo.SetRideAttachInfo( attachInfo1, attachInfo2 ); } //骑乘队员对骑乘队长切换地图的反应 void CPlayer::OnRideLeaderSwitchMap( const MGOnRideLeaderSwichMap* pMsg ) { if ( !pMsg ) return; CMapSrv* pOrgMapSrv = GetMapSrv(); if ( !pOrgMapSrv ) return; unsigned short newMap= pMsg->usMapID; unsigned short oldMap= pMsg->oldMapID; unsigned short iPosX = pMsg->iPosX; unsigned short iPosY = pMsg->iPosY; //1.通知原mapsrv玩家离开; GMPlayerLeave mapMsg; mapMsg.lPlayerID = GetPlayerID(); mapMsg.lMapCode = oldMap; mapMsg.nSpecialFlag = GMPlayerLeave::MAP_SWITCH_NORMAL;//骑乘队员只可能跳入普通地图而不能跳入副本地图,进副本地图需按常规路径; //MsgToPut* pNewMsg = CreateSrvPkg( GMPlayerLeave, pOrgMapSrv, mapMsg ); //pOrgMapSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMPlayerLeave, pOrgMapSrv, mapMsg ); //2.通知客户端目标地图信息; GCSwitchMap playerMsg; playerMsg.sequenceID = 0; playerMsg.playerID = GetPlayerID(); playerMsg.nErrCode = GCSwitchMap::OP_SUSSCESS; playerMsg.usMapID = newMap; playerMsg.iPosX = iPosX; playerMsg.iPosY = iPosY; //发送跳地图信息 NewSendPlayerPkg( GCSwitchMap, this, playerMsg ); //3.保存跳地图相关信息,玩家状态,更新玩家所在地图以及所在点; SetSwitchMapInfo( newMap, iPosX, iPosY /*既然是骑乘队员,则不可能是进副本*/ );//保存跳地图相关信息; //4.因为双人跳地图,进入地图后,玩家都不在骑乘状态 SetRideState( E_UNRIDE, 0 ,0); } //处于骑乘状态进入地图 void CPlayer::EnterWorldOnRideState() { CMapSrv* pMapsrv = GetMapSrv(); if ( !pMapsrv ) return; GMNewMapSetPlayerRideState newRideState; newRideState.playerID = GetPlayerID(); newRideState.rideState = m_rideTeamInfo.GetRideState(); newRideState.attachInfo = m_rideTeamInfo.GetRideAttachInfo1(); //MsgToPut* pNewMsg = CreateSrvPkg( GMNewMapSetPlayerRideState, pMapsrv, newRideState ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNewMapSetPlayerRideState, pMapsrv, newRideState ); } //玩家处于组队状态切换地图 void CPlayer::EnterWordOnGroupState() { //发送给RelationSrv请求组队 信息 QueryTeamRequest srvmsg; srvmsg.playerId = GetPlayerID().dwPID; srvmsg.gateId = GetPlayerID().wGID; srvmsg.teamInd = GetTeamId(); srvmsg.requestSeq = 0; //CRelationSrv* pRelationSrv = CManRelationSrvs::GetRelationserver(); //if( NULL == pRelationSrv ) //{ // D_ERROR("找不到RELATIONSRV\n"); // return; //} //MsgToPut* pNewMsg = CreateRelationPkg( QueryTeamRequest, pRelationSrv, srvmsg ); //pRelationSrv->SendPkgToSrv( pNewMsg ); SendMsgToRelationSrv( QueryTeamRequest, srvmsg ); } ///跳地图状态中,原地图发来玩家离开消息; void CPlayer::SwitchOrgMapSrvLeft() { if ( !IsInSwitching() ) { D_ERROR( "收到mapsrv的跳地图更新信息时,玩家不处于跳地图状态" ); return; } m_SwitchMapStat.OrgMapSrvLeft();//标记已离开原服务器; if ( !IsNextToCopy() ) { //如果下一跳不是进副本,则进行此检测; CMapSrv* pPlayerMapSrv = CDealMapSrvPkg::GetMapSrvByMapcode( GetMapID() ); if ( NULL != pPlayerMapSrv ) //重置玩家所在mapsrv为管理新地图的mapsrv; { D_DEBUG( "%s跳地图状态,收到原地图离开消息,目标:MapSrvID:%d, MapID:%d\n", GetAccount(), pPlayerMapSrv->GetID(), GetMapID() );//副本调试日志 SetMapSrvID( pPlayerMapSrv->GetID() ); } else { D_ERROR( "玩家跳地图离开原地图后,找不到管理新地图的mapsrv,踢此玩家%s下线\n", GetAccount() ); ReqDestorySelf(); return; } } if ( m_SwitchMapStat.IsEnterNewMapSrv() ) { //发进入新mapsrv请求; EnterMapSrv( false );//跳地图不用排队 } return; } ///置当前状态; bool CPlayer::SetCurStat( const PLAYER_STAT& curStat ) { TRY_BEGIN; //定义转换规则; if ( ( curStat == PS_LOGINING ) && ( m_CurStat != PS_CONN ) ) { D_WARNING( "玩家进入登录验证状态时,原状态非PS_CONN\n" ); return false; } if ( ( curStat == PS_LOGINED ) && ( m_CurStat != PS_LOGINING ) ) { D_WARNING( "玩家进入登录成功状态时,原状态非PS_LOGINING\n" ); return false; } if ( ( curStat == PS_CENTER_CHECKING ) && ( m_CurStat != PS_LOGINED ) ) { D_WARNING( "玩家进入PS_CENTER_CHECKING状态时,原状态非PS_LOGINED\n" ); return false; } if ( ( curStat == PS_CENTER_CHECKED ) && ( m_CurStat != PS_CENTER_CHECKING ) ) { D_WARNING( "玩家进入PS_CENTER_CHECKED状态时,原状态非PS_CONN\n" ); return false; } if ( ( curStat == PS_DB_LOGIN_QUERYING ) && ( m_CurStat != PS_CENTER_CHECKED ) ) { D_WARNING( "玩家进入PS_DB_LOGIN_QUERYING状态时,原状态非PS_CENTER_CHECKED\n" ); return false; } if ( ( curStat == PS_DB_LOGIN_QUERYED ) && ( m_CurStat != PS_DB_LOGIN_QUERYING ) ) { D_WARNING( "玩家进入PS_DB_LOGIN_QUERYED状态时,原状态非PS_DB_LOGIN_QUERYING\n" ); return false; } if ( curStat == PS_ROLESELED ) { D_DEBUG("玩家%s进入PS_ROLESELED状态\n",GetAccount()); if (( m_CurStat != PS_DB_LOGIN_QUERYED ) && (m_CurStat != PS_ROLESELED)) { D_WARNING( "玩家%s进入PS_ROLESELED状态时,原状态非PS_DB_LOGIN_QUERYED或PS_ROLESELED,原状态是%d\n", GetAccount(),m_CurStat ); if ( m_CurStat != PS_MAPFIGHTING ) { return false; } else { D_WARNING("玩家%s进入PS_ROLESELED状态时,原状态为PS_MAPFIGHTING\n", GetAccount()); } } } if ( ( curStat == PS_QUERY_DETAIL_INFO ) && (m_CurStat >= PS_QUERY_DETAIL_INFO) ) { D_WARNING( "玩家%s进入PS_QUERY_DETAIL_INFO状态时,原状态已经是PS_QUERY_DETAIL_INFO\n", GetAccount() ); return false; } //if ( ( curStat == PS_WORLDENTERING ) && ( m_CurStat != PS_ROLESELED ) ) //{ // D_WARNING( "玩家进入PS_WORLDENTERING状态时,原状态非PS_ROLESELED\n" ); // return false; //} if ( curStat == PS_DB_PRE ) { if ( ( m_CurStat == PS_DB_PRE ) || ( m_CurStat == PS_MAPFIGHTING ) ) { D_WARNING( "%s进PS_DB_PRE时原状态为%d,进入失败", GetAccount(), m_CurStat ); return false; } } if ( curStat == PS_MAPFIGHTING ) { D_DEBUG("玩家%s进入PS_MAPFIGHTING状态\n", GetAccount()); if (( m_CurStat != PS_DB_PRE ) && ( m_CurStat != PS_MAPFIGHTING )) { D_WARNING( "玩家%s进入PS_MAPFIGHTING状态时,原状态%d非PS_WORLDENTERING\n", GetAccount(), m_CurStat ); return false; } } m_CurStat = curStat; return true; TRY_END; return false; } ///向mapsrv发进入世界请求; void CPlayer::EnterMapSrv( bool isNeedQueueWait ) { TRY_BEGIN; //时间基准校验已过,向mapsrv发玩家出现消息; if ( !SetCurStat( PS_DB_PRE ) ) { //登录失败; D_WARNING( "CPlayer::EnterMapSrv, 置玩家%s进入PS_DB_PRE状态失败,断开连接\n", GetAccount() ); ReqDestorySelf();//断开连接; return; } m_SwitchMapStat.ResetSwitchMapStat( 0, 0, 0 );//清目标点信息; //每次进地图时递增进地图序号,用于比较同时来自不同地图的同一个人的信息的产生时间; ++ m_fullPlayerInfo.stateInfo.m_enterMapSeq; CMapSrv* pMapsrv = GetMapSrv();//找到mapserver,将相应包转发出去; if ( NULL == pMapsrv ) { GCSrvError srvError; srvError.errNO = 1001; NewSendPlayerPkg( GCSrvError, this, srvError ); D_WARNING( "玩家进入地图时,找不到其所在的mapsrv:%d\n\n", GetMapSrvID() ); return; } D_DEBUG( "CPlayer::EnterMapSrv,玩家%s进mapsrv:%d,mapid:%d\n", GetAccount(), pMapsrv->GetID(), GetMapID() ); SetMapSrvID( pMapsrv->GetID() ); PlayerDBInfoSend( isNeedQueueWait );//向map发送DB存盘信息 PlayerCopyInfoSend();//若玩家在副本中,则先通知玩家副本相关信息; std::vector vec; SendFullStr(&m_fullPlayerInfo, vec); for(std::vector::iterator i = vec.begin(); vec.end() != i; i++) { i->playerID = GetPlayerID(); SafeStrCpy( i->szAccount, m_fullPlayerInfo.baseInfo.szAccount );//MapSrv需要在第一个消息时就知道对应玩家的帐号,以便将其加入到全局管理器中去; i->sequenceID = 0; //MsgToPut* pNewMsg = CreateSrvPkg( GMFullPlayerInfo, pMapsrv, *i ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMFullPlayerInfo, pMapsrv, *i ); } //发送保护道具信息 PlayerProtectItemSend(); //发送任务存盘信息 PlayerTaskInfoSend(); PlayerNDSMRInfoSend();//向map发送非存盘,但跳地图保存信息; PlayerNDSMRCopyTeamInfoSend();//向mapsrv发送副本信息 //如果处于骑乘状态进入地图 if ( IsRideState() ) EnterWorldOnRideState(); //如果处于组队状态进入地图 2007.7.22 if ( IsInTeam() ) EnterWordOnGroupState(); //请求工会信息 QueryUnionInfo(); //若玩家在跳副本过程中离开了副本组队,则在此通知副本所在的mapsrv if ( m_copyInfo.m_isLeavedCopyTeam ) { m_copyInfo.m_isLeavedCopyTeam = false; NotiCopyMapSrvPlayerLeaveSTeam(); } //如果是GM账号则通知mapserver GMAccountNotify(); return; TRY_END; return; } //当玩家上线时 void CPlayer::OnPlayerRoleOnLine( char onlineType ) { CCenterSrv* pCenterSrv = CManCenterSrvs::GetCenterserver(); if ( NULL == pCenterSrv ) { D_ERROR("OnPlayerRoleOnLine, 找不到centersrv\n"); return; } GEPlayerRoleOnLine noticePlayerRoleOnLine; noticePlayerRoleOnLine.playerID = this->GetPlayerID(); SafeStrCpy( noticePlayerRoleOnLine.accountName, GetAccount() ); SafeStrCpy( noticePlayerRoleOnLine.playerName, GetRoleName() ); noticePlayerRoleOnLine.playerUID = this->GetRoleID(); //MsgToPut* pNewMsg1 = CreateSrvPkg( GEPlayerRoleOnLine, pCenterSrv, noticePlayerRoleOnLine ); //pCenterSrv->SendPkgToSrv( pNewMsg1 ); SendMsgToSrv( GEPlayerRoleOnLine, pCenterSrv, noticePlayerRoleOnLine ); #ifdef _DEBUG D_DEBUG("通知CentreSrv:玩家%s的%s角色上线\n", noticePlayerRoleOnLine.accountName, noticePlayerRoleOnLine.playerName ); #endif CLogManager::DoRoleEnterGame(this, (unsigned char)onlineType);//记录角色上线 CRelationSrv* pRelationSrv = CManRelationSrvs::GetRelationserver(); if ( NULL == pRelationSrv ) { D_ERROR("OnPlayerRoleOnLine, 找不到releationsrv\n"); return; } GRUplineInfo uplineMsg; StructMemSet(uplineMsg,0x0,sizeof(uplineMsg) ); uplineMsg.uiID = GetRoleID(); uplineMsg.player.GateSrvID =GetPlayerID().wGID; uplineMsg.player.PPlayer = GetPlayerID().dwPID; uplineMsg.MapID = GetMapID(); uplineMsg.playerClass = GetRoleClass(); uplineMsg.EnterModel = onlineType; uplineMsg.Sex = (char)(GetSex()); uplineMsg.playerIcon = GetPortraitID(); uplineMsg.playerRace = GetRoleRace(); uplineMsg.playerLevel = GetLevel(); SafeStrCpy( uplineMsg.Name, GetRoleName() ); uplineMsg.NameLen = (unsigned int) ( min( strlen( uplineMsg.Name ), sizeof(uplineMsg.Name) ) ); //MsgToPut* pNewMsg = CreateRelationPkg( GRUplineInfo, pRelationSrv, uplineMsg ); //pRelationSrv->SendPkgToSrv( pNewMsg ); SendMsgToRelationSrv( GRUplineInfo, uplineMsg ); #ifdef _DEBUG D_DEBUG("向RelationSrv发送玩家角色上线通知:%s\n",GetRoleName() ); #endif CShopSrv* pShopSrv = CManShopSrvs::GetShopserver(); if ( NULL == pShopSrv ) { D_ERROR("OnPlayerRoleOnLine, 找不到shopsrv\n"); return; } GSPlayerNotify onlineNotify; StructMemSet(onlineNotify, 0x00, sizeof(onlineNotify)); onlineNotify.NotifyType = PLAYERNOTIFY_ONLINE; PlayerID userId = GetPlayerID(); onlineNotify.UserId.dwPID = userId.dwPID; onlineNotify.UserId.wGID = userId.wGID; size_t accountLen = strlen(GetAccount()); onlineNotify.AccountLen = (BYTE)(accountLen <= sizeof(onlineNotify.Account) ? accountLen : sizeof(onlineNotify.Account)); //memcpy(onlineNotify.Account, GetAccount(), onlineNotify.AccountLen); StructMemCpy(onlineNotify.Account, GetAccount(), onlineNotify.AccountLen); onlineNotify.RoleID = GetSeledRole(); SafeStrCpy(onlineNotify.RoleName, GetRoleName()); onlineNotify.RoleNameLen = (BYTE)strlen(onlineNotify.RoleName); onlineNotify.RaceID= GetRace(); onlineNotify.ClassID = (UINT)GetClass(); onlineNotify.Level = (UINT)GetLevel(); //pNewMsg = CreateShopPkg(GSPlayerNotify, pShopSrv, onlineNotify); //pShopSrv->SendPkgToSrv( pNewMsg); SendMsgToShopSrv( GSPlayerNotify, onlineNotify ); #ifdef _DEBUG D_DEBUG("向ShopSrv发送玩家角色上线通知:%s\n",GetRoleName() ); #endif return; } //玩家更新自己在RelationSrv的信息 void CPlayer::OnUpdateSelfInfo( bool isOffLine, bool isSwitchCopy ) { CRelationSrv* pRelationSrv = CManRelationSrvs::GetRelationserver(); if ( !pRelationSrv ) return; GRInfoUpdate grInfoUpdate; StructMemSet( grInfoUpdate, 0x0, sizeof(GRInfoUpdate) ); grInfoUpdate.uiID = GetRoleID(); grInfoUpdate.Online = isOffLine?0x00:0x01; grInfoUpdate.playerClass = (CHAR) GetClass(); grInfoUpdate.playerLevel = GetLevel(); grInfoUpdate.playerIcon = GetPortraitID(); grInfoUpdate.playerRace = GetRoleRace(); if ( isSwitchCopy && (IsCurInCopy() || IsNextToCopy()) ) { //准备跳副本,发送副本地图号; grInfoUpdate.MapID = m_copyInfo.m_curCopyMapID; } else { //普通地图; grInfoUpdate.MapID = GetMapID(); } //MsgToPut* pNewMsg = CreateRelationPkg( GRInfoUpdate, pRelationSrv, grInfoUpdate ); //pRelationSrv->SendPkgToSrv( pNewMsg ); SendMsgToRelationSrv( GRInfoUpdate, grInfoUpdate ); #ifdef _DEBUG D_DEBUG("向RelationSrv发送更新玩家自身信息的消息\n"); #endif //teamcopyinfo /************************************************************************/ /*如果非组队玩家下线,通知centersrv结束玩家的单人副本组队状态,先发送GELeaveSTeamCenterNoti, 在发送GESTeamDestoryCenterNoti*/ /************************************************************************/ if( isOffLine ) { NotiPlayerEndSingleTeamCopyFlag(); } CShopSrv* pShopSrv = CManShopSrvs::GetShopserver(); if ( NULL == pShopSrv ) { D_ERROR("OnPlayerRoleOnLine, 找不到shopsrv\n"); return; } GSPlayerNotify onlineNotify; StructMemSet(onlineNotify, 0x00, sizeof(onlineNotify)); onlineNotify.NotifyType = PLAYERNOTIFY_OFFLINE; PlayerID userId = GetPlayerID(); onlineNotify.UserId.dwPID = userId.dwPID; onlineNotify.UserId.wGID = userId.wGID; size_t accountLen = strlen(GetAccount()); onlineNotify.AccountLen = (BYTE)(accountLen <= sizeof(onlineNotify.Account) ? accountLen : sizeof(onlineNotify.Account)); SafeStrCpy( onlineNotify.Account, GetAccount() );//, onlineNotify.AccountLen); onlineNotify.RoleID = GetSeledRole(); onlineNotify.RaceID= GetRace(); //pNewMsg = CreateShopPkg(GSPlayerNotify, pShopSrv, onlineNotify); //pShopSrv->SendPkgToSrv( pNewMsg); SendMsgToShopSrv( GSPlayerNotify, onlineNotify ); #ifdef _DEBUG D_DEBUG("向ShopSrv发送玩家角色离线通知:%s\n",GetRoleName() ); #endif } void CPlayer::SwichMapFailded( GCSwitchMap::ERR_T errNo ) { TRY_BEGIN; //2.通知客户端目标地图信息; GCSwitchMap playerMsg; playerMsg.playerID = this->GetPlayerID(); playerMsg.nErrCode = errNo; playerMsg.usMapID = 0; playerMsg.iPosX = 0; playerMsg.iPosY = 0; NewSendPlayerPkg( GCSwitchMap, this, playerMsg ); //MsgToPut* pNewMsg = CreatePlayerPkg( GCSwitchMap, this, playerMsg ); //SendPkgToPlayer( pNewMsg );//通知客户端 TRY_END; } ///返回角色选择 void CPlayer::OnPlayerReturnSelRole() { TRY_BEGIN; GMPlayerLeave playerLeave; playerLeave.nSpecialFlag = GMPlayerLeave::RETURN_SEL_ROLE; playerLeave.lMapCode = GetMapID();/*0;//没有特别的地图号;*/ playerLeave.lPlayerID = GetPlayerID(); CMapSrv* pMapSrv = GetMapSrv(); if ( NULL == pMapSrv ) { D_WARNING( "OnPlayerReturnSelRole,找不到玩家所在的mapsrv\n" ); return; } //MsgToPut* pNewMsg = CreateSrvPkg( GMPlayerLeave, pMapSrv, playerLeave ); //pMapSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMPlayerLeave, pMapSrv, playerLeave ); GERoleOffline roleLeave; roleLeave.playerID = GetPlayerID(); const char * roleName = GetRoleName(); if ( NULL != roleName ) { SafeStrCpy(roleLeave.szName,roleName); CCenterSrv* pCenterSrv = CManCenterSrvs::GetCenterserver(); if ( NULL == pCenterSrv ) { D_ERROR( "OnPlayerReturnSelRole,找不到centersrv\n" ); return; } //MsgToPut* pNewMsg = CreateSrvPkg( GERoleOffline, pCenterSrv, roleLeave ); //pCenterSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GERoleOffline, pCenterSrv, roleLeave ); } //关于组队的判断 if( IsInTeam() ) { RemoveTeamMemberRequest req; req.palyerId = GetPlayerID().dwPID; req.gateId = GetPlayerID().wGID; req.removedMode = 0; req.requestSeq = 0; req.teamInd = m_TeamInfo.GetTeamId(); CRelationSrv* pSrv = CManRelationSrvs::GetRelationserver(); if( NULL != pSrv ) { //pNewMsg = CreateRelationPkg( RemoveTeamMemberRequest, pSrv, req ); //pSrv->SendPkgToSrv( pNewMsg ); SendMsgToRelationSrv( RemoveTeamMemberRequest, req ); D_DEBUG("组队退出发送移除请求 退出人:%s\n", GetRoleName() ); } else { D_ERROR("CPlayer::OnDestoryed, 在组队中,找不到relationSrv\n"); //return; } } OnUpdateSelfInfo( true ); //将玩家状态重新置为选角色之前状态 ForceSetCurStat( PS_ROLESELED );//直接重置状态,绕过前置条件的检测 D_DEBUG("玩家返回人物选择,玩家: %s\n",GetAccount()); TRY_END; } ///mapsrv执行moveto/npc指令跳转 或 client跑到跳转点试图转跳,如果当前在普通地图,则直接调用SwitchMapCmd,否则,如果在副本中,则首先排除副本跳副本,然后保存OutMapInfo,然后向center发离开副本请求; bool CPlayer::OnMapOrPlayerSwitchReq( unsigned int newMap, unsigned int targetPosX, unsigned int targetPosY ) { TRY_BEGIN; if ( !IsInFighting() ) { D_WARNING( "玩家%s尚未进入战斗状态,不应该切换地图\n", GetAccount() ); SwichMapFailded(); return false; } if ( IsInSwitching() ) { D_WARNING( "玩家%s在跳地图中,不再理会新的跳地图请求\n", GetAccount() ); SwichMapFailded(); return false; } CMapSrv* pOrgMapSrv = GetMapSrv(); if ( NULL == pOrgMapSrv ) { D_WARNING( "OnMapOrPlayerSwitchReq,玩家%s,NULL == pOrgMapSrv\n", GetAccount() ); SwichMapFailded(); return false; } if ( !IsCurInCopy() ) { //当前在普通地图中,直接调用SwitchMapCmd; SwitchMapCmd( pOrgMapSrv, newMap, targetPosX, targetPosY ); return true; } if ( IsCurPCopy() ) { ///若为伪副本,则设置outmapinfo后调用SwitchMapCmd; SetOutMapInfo( newMap, targetPosX, targetPosY ); SwitchMapCmd( pOrgMapSrv, newMap, targetPosX, targetPosY ); return true; } //以下为从真副本中跳出的处理; //从真副本中跳出,1.保存副本外位置;2.向center发离开副本请求; SetOutMapInfo( newMap, targetPosX, targetPosY ); //通知center玩家离开副本请求; NotiCenterPlayerLeaveCopyQuest( m_copyInfo.m_curCopyID/*副本id号*/, m_copyInfo.m_curCopyMapID/*副本地图号*/, GetAccount()/*玩家帐号*/ ); return true; TRY_END; return false; } bool CPlayer::SwitchMapCmd( CMapSrv* pOrgMapSrv, unsigned int newMapID, unsigned int targetPosX, unsigned int targetPosY, bool normalSwitchOrCopy/*普通跳地图(true)或是进副本(false)*/ ) { if ( NULL == pOrgMapSrv ) { D_ERROR( "CPlayer::SwitchMapCmd,NULL == pOrgMapSrv\n" ); SwichMapFailded(); return false; } if ( !IsInFighting() ) { D_WARNING( "玩家%s尚未进入战斗状态,不应该切换地图\n", GetAccount() ); SwichMapFailded(); return false; } if ( IsInSwitching() ) { D_WARNING( "玩家%s在跳地图中,不再理会新的跳地图请求\n", GetAccount() ); SwichMapFailded(); return false; } if ( !normalSwitchOrCopy ) { ////跳副本; //if ( IsCurInCopy() ) //{ // //若当前在副本中,则禁止; // D_ERROR( "玩家%s副本中跳副本,禁止\n", GetAccount() ); // return false; //} } bool isOnRide = (GetRideState() == E_RIDE_EQUIP && IsHasAttachInfo()); if ( !normalSwitchOrCopy ) { //进副本跳地图,双人以上不可进副本; if ( isOnRide ) { D_ERROR( "%s试图双人以上进副本", GetAccount() ); SwichMapFailded(); return false; } } if ( normalSwitchOrCopy ) { //普通跳地图,检查目标地图是否可进,若为副本,则不必进行此项检查,因为副本已在原mapsrv创建好,等待玩家进入; CMapSrv* pNewMapSrv = CDealMapSrvPkg::GetMapSrvByMapcode( newMapID ); if ( NULL == pNewMapSrv ) { D_WARNING( "目标地图满调试,玩家%s跳地图时,找不到目标地图%d所在的mapsrv\n", GetAccount(), newMapID ); SwichMapFailded(); return false; } if ( !pNewMapSrv->IsCanEnter() ) { //目标mapsrv空或者人数已满不可进; D_WARNING( "目标地图满调试,玩家%s跳地图时,目标地图%d满\n", GetAccount(), newMapID ); SwichMapFailded( GCSwitchMap::TGT_MAP_FULL ); return false; } } int iPosX = 0 , iPosY = 0; unsigned short usMapID = 0; if ( !(GetCurPos( iPosX, iPosY )) ) { D_ERROR( "跳地图时,不能确定玩家%s当前所在点\n", GetAccount() ); SwichMapFailded(); return false; } if ( !(GetCurMapID( usMapID )) ) { D_ERROR( "跳地图时,不能确定玩家%s当前所在地图\n", GetAccount() ); SwichMapFailded(); return false; } //1.通知原mapsrv玩家离开; //2.通知客户端目标地图信息; //3.保存跳地图相关信息,玩家状态,更新玩家所在地图以及所在点; //1.通知原mapsrv玩家离开; GMPlayerLeave mapMsg; mapMsg.lPlayerID = GetPlayerID(); mapMsg.lMapCode = GetMapID(); if ( normalSwitchOrCopy ) { //普通跳地图; mapMsg.nSpecialFlag = GMPlayerLeave::MAP_SWITCH_NORMAL; } else { //跳入副本地图; mapMsg.nSpecialFlag = GMPlayerLeave::MAP_SWITCH_COPY; } //MsgToPut* pNewMsg = CreateSrvPkg( GMPlayerLeave, pOrgMapSrv, mapMsg ); //pOrgMapSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMPlayerLeave, pOrgMapSrv, mapMsg ); //2.如果处于双人骑乘状态,则还要通知被骑乘玩家跳地图 if ( isOnRide ) { GCMountTeamDisBand disbandMsg; disbandMsg.mountTeamID = GetPlayerID(); NewSendPlayerPkg( GCMountTeamDisBand, this , disbandMsg ); GMRideLeaderSwitchMap swichMap; swichMap.iPosX = targetPosX; swichMap.iPosY = targetPosY; GetRideAttachInfo( swichMap.playerID.dwPID, swichMap.playerID.wGID ); swichMap.oldMapID = usMapID; swichMap.usMapID = newMapID; //MsgToPut* pSwichMsg = CreateSrvPkg( GMRideLeaderSwitchMap, pOrgMapSrv, swichMap ); //pOrgMapSrv->SendPkgToSrv( pSwichMsg ); SendMsgToSrv( GMRideLeaderSwitchMap, pOrgMapSrv, swichMap ); //双人跳地图后都需要下马 SetRideState( E_UNRIDE, 0,0 ); } //3.通知客户端目标地图信息; GCSwitchMap playerMsg; playerMsg.sequenceID = 0; playerMsg.playerID = GetPlayerID(); playerMsg.nErrCode = GCSwitchMap::OP_SUSSCESS; playerMsg.usMapID = newMapID; playerMsg.iPosX = targetPosX; playerMsg.iPosY = targetPosY; NewSendPlayerPkg( GCSwitchMap, this, playerMsg ); //pNewMsg = CreatePlayerPkg( GCSwitchMap, this, playerMsg ); //SendPkgToPlayer( pNewMsg );//通知客户端 //3.保存跳地图相关信息,玩家状态,更新玩家所在地图以及所在点; SetSwitchMapInfo( newMapID, targetPosX, targetPosY, normalSwitchOrCopy );//保存跳地图相关信息; return true; } //玩家进副本命令处理 bool CPlayer::OnPlayerEnterRealCopyCmd( EGEnterCopyCmd* pEnterCopyInfo ) { if ( NULL == pEnterCopyInfo ) { return false; } unsigned short mapID=0; int posX=0, posY=0; GetCurPos( posX, posY ); GetCurMapID( mapID ); CMapSrv* pOrgMapSrv = GetMapSrv(); if ( NULL == pOrgMapSrv ) { D_ERROR( "玩家%s跳副本(copyid:%d,mapid:%d)失败,找不到其原来所在的mapsrv,踢下线\n" , GetAccount(), pEnterCopyInfo->copyInfo.copyID, pEnterCopyInfo->copyInfo.enterReq.copyMapID ); ReqDestorySelf(); return false; } m_copyInfo.m_isPCopy = false;//真副本; m_copyInfo.m_curCopyID = pEnterCopyInfo->copyInfo.copyID; m_copyInfo.m_curCopyMapID = pEnterCopyInfo->copyInfo.enterReq.copyMapID; m_copyInfo.m_toUseScrollType = pEnterCopyInfo->scrollType;//需扣的副本券数量,由centersrv决定是否扣,扣多少; m_copyInfo.m_isNextCopy = true; m_copyInfo.m_MapSrvID = pEnterCopyInfo->copyInfo.mapsrvID; m_copyInfo.m_outMapID = mapID; m_copyInfo.m_outMapPosX = posX; m_copyInfo.m_outMapPosY = posY; m_copyInfo.m_isLeavedCopyTeam = false;//初始没有离开副本所在组队; if ( !SwitchMapCmd( pOrgMapSrv, m_copyInfo.m_curCopyMapID, 0, 0, false/*switch to copy*/ ) ) { //跳副本失败,踢玩家下线,以维护center的副本逻辑; D_ERROR( "玩家%s跳副本(copyid:%d,mapid:%d)失败,踢下线以维护center上的逻辑\n", GetAccount(), m_copyInfo.m_curCopyID, m_copyInfo.m_curCopyMapID ); ReqDestorySelf(); return false; } //如果玩家跳普通地图,则之前会正确地清outmapinfo, // 如果是跳副本,则在更新fullplayerinfo(及其内部的mapid与x,y)时,mapsrv必定会同时发来本copyInfo,在此设置相应的outmapinfo, // 因此总能正确地设置OutMapInfo,并将其作为玩家存DB依据; SetOutMapInfo( mapID, posX, posY );//保存outmapinfo; return true; } ///玩家进伪副本命令处理 bool CPlayer::OnPlayerEnterPCopyCmd( unsigned int scrollType, unsigned short pcopyMapID ) { if ( scrollType <= 0 ) { //伪副本固定扣一个副本券,若玩家身上没有副本券,则不能进伪副本,本应在mapsrv拦住,若mapsrv没拦住,则此处拦住; D_ERROR( "玩家%s进伪副本%d,但其身上无副本券\n", GetAccount(), pcopyMapID ); return false; } unsigned short mapID=0; int posX=0, posY=0; GetCurPos( posX, posY ); GetCurMapID( mapID ); CMapSrv* pPCopyMapSrv = CDealMapSrvPkg::GetMapSrvByMapcode( pcopyMapID ); if ( NULL == pPCopyMapSrv ) { D_ERROR( "OnPlayerEnterPCopyCmd,找不到管理伪副本%d的mapsrv\n", pcopyMapID ); return false; } unsigned short pcopyMapSrvID = pPCopyMapSrv->GetID(); CMapSrv* pOrgMapSrv = GetMapSrv(); if ( NULL == pOrgMapSrv ) { D_ERROR( "玩家%s跳伪副本(mapid:%d)失败,找不到其原来所在的mapsrv\n" , GetAccount(), pcopyMapID ); return false; } m_copyInfo.m_isPCopy = true;//伪副本; m_copyInfo.m_curCopyID = 0;//伪副本无副本实例号 m_copyInfo.m_curCopyMapID = pcopyMapID; m_copyInfo.m_toUseScrollType = 1;//需扣的副本券数量,伪副本固定为1; m_copyInfo.m_isNextCopy = true; m_copyInfo.m_MapSrvID = pcopyMapSrvID; if ( !IsCurInCopy() ) { //普通地图跳伪副本时,使用当前地图信息作为outmapinfo; m_copyInfo.m_outMapID = mapID; m_copyInfo.m_outMapPosX = posX; m_copyInfo.m_outMapPosY = posY; } else { //伪副本跳伪副本时,使用前次伪副本的outmapinfo; m_copyInfo.m_outMapID = m_outMapInfo.usMapID; m_copyInfo.m_outMapPosX = m_outMapInfo.iPosX; m_copyInfo.m_outMapPosY = m_outMapInfo.iPosY; } m_copyInfo.m_isLeavedCopyTeam = false;//初始没有离开副本所在组队; if ( !SwitchMapCmd( pOrgMapSrv, m_copyInfo.m_curCopyMapID, 0, 0, false/*switch to copy*/ ) ) { //跳副本失败,踢玩家下线,以维护center的副本逻辑; D_ERROR( "玩家%s跳伪副本(copyid:%d,mapid:%d)失败,踢下线以维护逻辑完整\n", GetAccount(), m_copyInfo.m_curCopyID, m_copyInfo.m_curCopyMapID ); ReqDestorySelf(); return false; } //如果玩家跳普通地图,则之前会正确地清outmapinfo, // 如果是跳副本,则在更新fullplayerinfo(及其内部的mapid与x,y)时,mapsrv必定会同时发来本copyInfo,在此设置相应的outmapinfo, // 因此总能正确地设置OutMapInfo,并将其作为玩家存DB依据; if ( !IsCurInCopy() ) { //允许伪副本跳伪副本,此时不更新outmapinfo; SetOutMapInfo( mapID, posX, posY );//保存outmapinfo; } return true; } //玩家离开真副本命令处理 bool CPlayer::OnPlayerLeaveRealCopyCmd( EGLeaveCopyCmd* pLeaveCopyInfo ) { if ( NULL == pLeaveCopyInfo ) { return false; } CMapSrv* pOrgMapSrv = GetMapSrv(); if ( NULL == pOrgMapSrv ) { D_ERROR( "玩家%s离开真副本失败,找不到其原来所在的mapsrv,踢其下线\n", GetAccount() ); ReqDestorySelf(); return false; } if ( !(m_outMapInfo.isOutMapInfoSet ) ) { D_ERROR( "玩家%s离开副本,但没有设置该玩家的outmapinfo,踢其下线\n", GetAccount() ); ReqDestorySelf(); return false; } D_DEBUG( "玩家%s离开副本,存DB时存其副本外位置%d(%d,%d)\n", GetAccount(), m_outMapInfo.usMapID, m_outMapInfo.iPosX, m_outMapInfo.iPosY ); m_fullPlayerInfo.baseInfo.usMapID = m_outMapInfo.usMapID; m_fullPlayerInfo.baseInfo.iPosX = m_outMapInfo.iPosX; m_fullPlayerInfo.baseInfo.iPosY = m_outMapInfo.iPosY; if ( !SwitchMapCmd( pOrgMapSrv, m_outMapInfo.usMapID, m_outMapInfo.iPosX, m_outMapInfo.iPosY ) ) { //从副本回普通地图失败,踢玩家下线,以维护center的副本逻辑; D_ERROR( "玩家%s跳回普通地图(mapid:%d)失败,踢下线以维护center上的逻辑\n", GetAccount(), m_fullPlayerInfo.baseInfo.usMapID ); ReqDestorySelf(); return false; } return true; } ///玩家离开伪副本命令处理 bool CPlayer::OnPlayerLeavePCopyCmd() { CMapSrv* pOrgMapSrv = GetMapSrv(); if ( NULL == pOrgMapSrv ) { D_ERROR( "玩家%s离开伪副本失败,找不到其原来所在的mapsrv,踢其下线\n", GetAccount() ); ReqDestorySelf(); return false; } if ( !(m_outMapInfo.isOutMapInfoSet ) ) { D_ERROR( "玩家%s离开伪副本,但没有设置该玩家的outmapinfo,踢其下线\n", GetAccount() ); ReqDestorySelf(); return false; } D_DEBUG( "玩家%s离开伪副本,存DB时存其副本外位置%d(%d,%d)\n", GetAccount(), m_outMapInfo.usMapID, m_outMapInfo.iPosX, m_outMapInfo.iPosY ); m_fullPlayerInfo.baseInfo.usMapID = m_outMapInfo.usMapID; m_fullPlayerInfo.baseInfo.iPosX = m_outMapInfo.iPosX; m_fullPlayerInfo.baseInfo.iPosY = m_outMapInfo.iPosY; if ( !SwitchMapCmd( pOrgMapSrv, m_outMapInfo.usMapID, m_outMapInfo.iPosX, m_outMapInfo.iPosY ) ) { //从副本回普通地图失败,踢玩家下线,以维护center的副本逻辑; D_ERROR( "玩家%s跳回普通地图(mapid:%d)失败,踢下线以维护center上的逻辑\n", GetAccount(), m_fullPlayerInfo.baseInfo.usMapID ); ReqDestorySelf(); return false; } return true; } ///通知真副本所在mapsrv,副本中玩家已离开了副本所属组队 bool CPlayer::NotiCopyMapSrvPlayerLeaveSTeam() { //消息转发mapsrv; GMLeaveSTeamNoti leaveSTeamNoti; leaveSTeamNoti.leavePlayerID = GetPlayerID(); CMapSrv* pMapSrv = GetMapSrv(); if ( NULL == pMapSrv ) { D_WARNING( "CPlayer::NotiCopyMapSrvPlayerLeaveSTeam,找不到玩家%s所在的mapsrv\n", GetAccount() ); return false; } D_DEBUG( "通知真副本服务器,玩家%d已离开副本组队\n", GetPlayerID().dwPID ); //MsgToPut* pNewMsg = CreateSrvPkg( GMLeaveSTeamNoti, pMapSrv, leaveSTeamNoti ); //pMapSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMLeaveSTeamNoti, pMapSrv, leaveSTeamNoti ); return true; } ///玩家离开组队时也准备通知该玩家当前所在的副本; bool CPlayer::OnPlayerLeaveSteam( unsigned int leavecopyID ) { //若此消息在跳地图过程中来到,则新mapsrv将无法正确处理。 if ( IsInSwitching() ) { //在玩家身上记录此消息,以便在玩家真正进入副本mapsrv后再通知mapsrv; if ( leavecopyID != m_copyInfo.m_curCopyID ) { D_ERROR( "CPlayer::OnPlayerLeaveSteam, leavecopyID != m_copyInfo.m_curCopyID\n" ); return false; } else { //记录此离开信息,准备在玩家进入副本后,向副本所在mapsrv发此玩家离开组队消息,以便其处理; D_DEBUG( "小概率事件,玩家还未真正跳入真副本%d的情况下,就离开了副本所属组队,准备延后通知真副本服务器\n", leavecopyID ); m_copyInfo.m_isLeavedCopyTeam = true; return true; } } //非跳地图状态中,直接通知mapsrv NotiCopyMapSrvPlayerLeaveSTeam(); return true; } ////DB取信息开始; Register( D_G_DBGET_PRE, &OnDbGetPre ); bool CPlayer::OnDbGetPre( const DGDbGetPre* pDbGetPre ) { TRY_BEGIN; if ( NULL == pDbGetPre ) { D_ERROR( "OnDbGetPre,输入信息空\n" ); return false; } if ( m_DBGetInfo.isValid ) { D_ERROR( "OnDbGetPre,未接到GetPost的情形下再次收到GetPre\n" ); return false; } m_DBGetInfo.isValid = true; m_DBGetInfo.protectInfoVec.clear(); return true; TRY_END; return false; }; ////DB取信息结束(与M_G_DBSAVE_POST一一对应); Register( D_G_DBGET_POST, &OnDbGetPost ); bool CPlayer::OnDbGetPost( const DGDbGetPost* pDbGetPost ) { TRY_BEGIN; if ( NULL == pDbGetPost ) { D_ERROR( "OnDbGetPost,输入信息空\n" ); return false; } if ( !(m_DBGetInfo.isValid) ) { D_ERROR( "OnDbGetPost,未接到GetPre的情形下收到GetPost\n" ); return false; } //以下向mapsrv发送该玩家的存盘信息; return true; TRY_END; return false; }; ////DB保存信息; Register( D_G_DBGET_INFO, &OnDbGetInfo ); bool CPlayer::OnDbGetInfo( const DGDbGetInfo* pDbGetInfo ) { TRY_BEGIN; if ( NULL == pDbGetInfo ) { D_ERROR( "OnDbGetInfo,输入信息空\n" ); return false; } if ( !(m_DBGetInfo.isValid) ) { D_ERROR( "OnDbGetInfo,未接到GetPre的情形下收到GetInfo\n" ); return false; } //以下保存该玩家的存盘信息; switch ( pDbGetInfo->infoType ) { case (DI_PET): { StructMemCpy( (m_DBGetInfo.petInfo), &(pDbGetInfo->petInfo), sizeof(m_DBGetInfo.petInfo) ); break; } case (DI_SUIT): { StructMemCpy( (m_DBGetInfo.suitInfo), &(pDbGetInfo->suitInfo), sizeof(m_DBGetInfo.suitInfo) ); break; } case (DI_FASHION): { StructMemCpy( (m_DBGetInfo.fashionInfo), &(pDbGetInfo->fashionInfo), sizeof(m_DBGetInfo.fashionInfo) ); break; } case (DI_PROTECTITEM): { if ( 0 == pDbGetInfo->protectInfo.mCount ) { m_DBGetInfo.protectInfoVec.clear(); } m_DBGetInfo.protectInfoVec.push_back( pDbGetInfo->protectInfo ); break; } case (DI_TASKRD): { StructMemCpy( m_DBGetInfo.taskRdInfo, &pDbGetInfo->taskRdInfo, sizeof(m_DBGetInfo.taskRdInfo) ); break; } case (DI_COPYSTAGE): { StructMemCpy( m_DBGetInfo.copyStageInfos, &pDbGetInfo->copyStageInfos, sizeof(m_DBGetInfo.copyStageInfos) ); break; } default: { D_WARNING( "OnDbGetInfo,不可识别的DB存盘信息类型%d", pDbGetInfo->infoType ); } }; return true; TRY_END; return false; }; void CPlayer::PlayerProtectItemSend() { CMapSrv* pMapsrv = GetMapSrv();//找到mapserver,将相应包转发出去; if ( NULL == pMapsrv ) { D_ERROR( "PlayerProtectItemSend,找不到玩家所在mapsrv\n" ); return; } GMDbGetInfo getInfo; getInfo.playerID = GetPlayerID(); getInfo.infoType = DI_PROTECTITEM; unsigned int count = (unsigned int)m_DBGetInfo.protectInfoVec.size(); if ( count > 0 ) { for ( unsigned int i = 0 ; i< count; i++ ) { StructMemSet( getInfo.protectItemInfo, 0x0, sizeof(getInfo.protectItemInfo) ); ProtectItemInfo& protectItemInfo = m_DBGetInfo.protectInfoVec[i]; StructMemCpy( getInfo.protectItemInfo, &protectItemInfo, sizeof(getInfo.protectItemInfo) ); //MsgToPut* pNewMsg = CreateSrvPkg( GMDbGetInfo, pMapsrv, getInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMDbGetInfo, pMapsrv, getInfo ); } } } void CPlayer::PlayerTaskInfoSend() { CMapSrv* pMapsrv = GetMapSrv();//找到mapserver,将相应包转发出去; if ( NULL == pMapsrv ) { D_ERROR( "PlayerTaskInfoSend,找不到玩家所在mapsrv\n" ); return; } GMDbGetInfo getInfo; getInfo.playerID = GetPlayerID(); getInfo.infoType = DI_TASKRD; StructMemCpy( getInfo.taskRdInfo, &m_DBGetInfo.taskRdInfo, sizeof(getInfo.taskRdInfo) ); //MsgToPut* pNewMsg = CreateSrvPkg( GMDbGetInfo, pMapsrv, getInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMDbGetInfo, pMapsrv, getInfo ); } void CPlayer::RecvMGProtectItemInfo( const ProtectItemInfo& protectItem ) { if ( protectItem.mCount == 0 ) m_DBGetInfo.protectInfoVec.clear(); m_DBGetInfo.protectInfoVec.push_back( protectItem ); } void CPlayer::RecvMGTaskRecordInfo( const TaskRdInfo& taskRdInfo ) { StructMemCpy( m_DBGetInfo.taskRdInfo, &taskRdInfo, sizeof(m_DBGetInfo.taskRdInfo) ); } void CPlayer::RecvMGSuitInfo(const PlayerInfo_Suits &suits) { StructMemCpy( m_DBGetInfo.suitInfo, &suits, sizeof(m_DBGetInfo.suitInfo)); } void CPlayer::RecvMGFashionInfo(const PlayerInfo_Fashions &fashion) { StructMemCpy( m_DBGetInfo.fashionInfo, &fashion, sizeof(m_DBGetInfo.fashionInfo)); } ///在gatesrv上保存玩家副本阶段信息副本; void CPlayer::RecvMGCopyStageInfo( const PlayerStageInfos& playerStageInfos ) { StructMemCpy( m_DBGetInfo.copyStageInfos, &playerStageInfos, sizeof(m_DBGetInfo.copyStageInfos) ); } ///向centersrv发送离开副本请求 bool CPlayer::NotiCenterPlayerLeaveCopyQuest( unsigned int copyID/*副本id号*/, unsigned short copyMapID/*副本地图号*/, const char* playerAccount/*玩家帐号*/ ) { if ( NULL == playerAccount ) { D_ERROR( "CPlayer::NotiCenterPlayerLeaveCopyQuest, NULL == playerAccount" ); return false; } GEPlayerLeaveCopyQuest playerLeaveCopy; StructMemSet( playerLeaveCopy, 0, sizeof(playerLeaveCopy) ); playerLeaveCopy.leaveCopyPlayerID = GetPlayerID(); playerLeaveCopy.leaveCopyInfo.enterReq.playerID = GetPlayerID(); playerLeaveCopy.leaveCopyInfo.copyID = copyID; playerLeaveCopy.leaveCopyInfo.enterReq.copyMapID = copyMapID; SafeStrCpy( playerLeaveCopy.leaveCopyInfo.enterReq.szAccount, playerAccount ); CCenterSrv* pCenterSrv = CManCenterSrvs::GetCenterserver(); if ( NULL == pCenterSrv ) { D_WARNING( "CDealPlayerPkg::NotiCenterPlayerLeaveCopyQuest找不到CenterSrv\n" ); return false; } //MsgToPut* pNewMsg = CreateSrvPkg( GEPlayerLeaveCopyQuest, pCenterSrv, playerLeaveCopy ); //pCenterSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GEPlayerLeaveCopyQuest, pCenterSrv, playerLeaveCopy ); return true; } bool CPlayer::NotiPlayerEndSingleTeamCopyFlag() { if ( IsInTeam() ) { //只在单人的情况下,发送副本相应编号的变化消息 GELeaveSTeamCenterNoti leaveteam; StructMemSet( leaveteam, 0, sizeof(leaveteam) ); leaveteam.leavePlayerID = GetPlayerID(); leaveteam.steamID = GetPlayerCopyFlag(); SafeStrCpy( leaveteam.szNickName, GetRoleName() ); SendMsgToCenterSrv( GELeaveSTeamCenterNoti, leaveteam ); D_DEBUG("玩家 %s 结束多人组队状态,向centersrv发送消息GELeaveSTeamCenterNoti 组队编号:%d\n", GetRoleName(), leaveteam.steamID ); } else { //只在单人的情况下,发送副本相应编号的变化消息 GELeaveSTeamCenterNoti leaveteam; StructMemSet( leaveteam, 0, sizeof(leaveteam) ); leaveteam.leavePlayerID = GetPlayerID(); leaveteam.steamID = GetPlayerCopyFlag(); SafeStrCpy( leaveteam.szNickName, GetRoleName() ); SendMsgToCenterSrv( GELeaveSTeamCenterNoti, leaveteam ); GESTeamDestoryCenterNoti destoryteam; destoryteam.steamID = GetPlayerCopyFlag(); SendMsgToCenterSrv( GESTeamDestoryCenterNoti,destoryteam ); D_DEBUG("玩家 %s 结束单人组队状态,向centersrv发送消息GELeaveSTeamCenterNoti 和 GESTeamDestoryCenterNoti,单人组队编号:%d\n", GetRoleName(), leaveteam.steamID ); } return true; } bool CPlayer::IsTeamCopyInfoLeader() { if ( IsInTeam() )//如果组队状态 { return IsTeamCaptain();//是否是组队队长 } return true;//单人情况直接返回true } ///玩家可能的副本信息通知对应mapsrv; bool CPlayer::PlayerCopyInfoSend() { if ( !IsNextToCopy() ) { //不是跳副本; m_isCurInCopy = false;//标记----玩家不在副本中; return false; } CMapSrv* pMapSrv = GetMapSrv(); if ( NULL == pMapSrv ) { return false; } //若玩家在副本中,则先通知玩家副本相关信息; GMNDSMRInfo nInfo; //特殊,利用GMNDSMRInfo来发送跳副本信息; nInfo.playerID = GetPlayerID(); //有跟随怪物; nInfo.infoType = NI_COPY_INFO; nInfo.copyInfo = m_copyInfo; //MsgToPut* pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapSrv, nInfo ); //pMapSrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapSrv, nInfo ); m_copyInfo.m_isNextCopy = false;//当前已离开原地图,已向真正副本地图发送fullinfo; m_isCurInCopy = true;//标记----玩家在副本中; return true; } ///自身取到的存盘信息送map; bool CPlayer::PlayerDBInfoSend( bool isNeedQueueCheck ) { TRY_BEGIN; if ( !(m_DBGetInfo.isValid) ) { D_ERROR( "PlayerDBInfoSend,未收完DBINFO\n" ); return false; } CMapSrv* pMapsrv = GetMapSrv();//找到mapserver,将相应包转发出去; if ( NULL == pMapsrv ) { D_ERROR( "PlayerDBInfoSend,找不到玩家所在mapsrv\n" ); return false; } /* 1.send DBGetPre 2.send 各信息 3.send DBGetPost */ //1.send DBGetPre GMDbGetPre getPre; getPre.playerID = GetPlayerID(); getPre.isNeedQueueCheck = isNeedQueueCheck; SafeStrCpy( getPre.roleName, GetRoleName() ); SafeStrCpy( getPre.accountName, GetAccount() ); //MsgToPut* pNewMsg = CreateSrvPkg( GMDbGetPre, pMapsrv, getPre ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMDbGetPre, pMapsrv, getPre ); //2.send 各信息 GMDbGetInfo getInfo; getInfo.playerID = GetPlayerID(); getInfo.infoType = DI_PET; StructMemCpy( (getInfo.petInfo), &(m_DBGetInfo.petInfo), sizeof(getInfo.petInfo) ); //pNewMsg = CreateSrvPkg( GMDbGetInfo, pMapsrv, getInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMDbGetInfo, pMapsrv, getInfo ); getInfo.infoType = DI_SUIT; StructMemCpy( (getInfo.suitInfo), &(m_DBGetInfo.suitInfo), sizeof(getInfo.suitInfo) ); //pNewMsg = CreateSrvPkg( GMDbGetInfo, pMapsrv, getInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMDbGetInfo, pMapsrv, getInfo ); getInfo.infoType = DI_FASHION; StructMemCpy( (getInfo.fashionInfo), &(m_DBGetInfo.fashionInfo), sizeof(getInfo.fashionInfo) ); //pNewMsg = CreateSrvPkg( GMDbGetInfo, pMapsrv, getInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMDbGetInfo, pMapsrv, getInfo ); getInfo.infoType = DI_COPYSTAGE; StructMemCpy( (getInfo.copyStageInfos), &(m_DBGetInfo.copyStageInfos), sizeof(getInfo.copyStageInfos) ); //pNewMsg = CreateSrvPkg( GMDbGetInfo, pMapsrv, getInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMDbGetInfo, pMapsrv, getInfo ); /*getInfo.infoType = DI_PROTECTITEM; StructMemCpy( getInfo.protectItemInfo, &m_DBGetInfo.protectInfo, sizeof(getInfo.protectItemInfo) ); pNewMsg = CreateSrvPkg( GMDbGetInfo, pMapsrv, getInfo ); pMapsrv->SendPkgToSrv( pNewMsg );*/ /*getInfo.infoType = DI_TASKRD; StructMemCpy( getInfo.taskRdInfo, &m_DBGetInfo.taskRdInfo, sizeof(getInfo.taskRdInfo) ); pNewMsg = CreateSrvPkg( GMDbGetInfo, pMapsrv, getInfo ); pMapsrv->SendPkgToSrv( pNewMsg );*/ //3.send DBGetPost GMDbGetPost getPost; getPost.playerID = GetPlayerID(); //pNewMsg = CreateSrvPkg( GMDbGetPost, pMapsrv, getPost ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMDbGetPost, pMapsrv, getPost ); return true; TRY_END; return false; }; ///收到mapsrv发来NDSMR信息时的处理; void CPlayer::OnMapNDSMRInfo( const MGNDSMRInfo* pMGInfo ) { if ( NULL == pMGInfo ) { return; } //以下保存该玩家的存盘信息; switch ( pMGInfo->infoType ) { case (NI_FOLLOW_MONSTER): { m_ndsmrInfo.followMonsterType = pMGInfo->followMonsterType; break; } case NI_ROGUE_TIME: { m_ndsmrInfo.rogueTime = pMGInfo->rogueTime; break; } #ifdef ANTI_ADDICTION case NI_GAME_STATE: { m_ndsmrInfo.gameState = pMGInfo->gameState; break; } #endif //ANTI_ADDICTION case NI_PET_INFO: { if ( DI_PET == pMGInfo->petInfo.infoType ) //保存的确实是宠物信息 { StructMemCpy( (m_ndsmrInfo.petInfo), &(pMGInfo->petInfo.petInfo), sizeof(m_ndsmrInfo.petInfo) ); } break; } case NI_BATTLE_MODE: { m_ndsmrInfo.battleMode = pMGInfo->battleMode; break; } case NI_KILL_COUNTER: { m_ndsmrInfo.punishTaskInfo = pMGInfo->punishTaskInfo; break; } case NI_PET_TIMER: { m_ndsmrInfo.petTimer = pMGInfo->petTimer; break; } case NI_ANAMORPHIC_STATE: { m_ndsmrInfo.anamorphicState = pMGInfo->anamorphicState; break; } case NI_WAR_TASK: { m_ndsmrInfo.warTaskId = pMGInfo->warTaskId; break; } case NI_STORAGE_INFO: { m_ndsmrInfo.storageLock = pMGInfo->storageLock; break; } case NI_ROOKIE_BREAK_TIME: { m_ndsmrInfo.rookieBreakTime = pMGInfo->rookieBreakTime; break; } case NI_BUFF_DATA: { m_ndsmrInfo.tpBuffData = pMGInfo->tpBuffData; break; } case NI_KILL_INFO: { m_ndsmrInfo.killInfo = pMGInfo->killInfo; } break; default: { D_WARNING( "OnMapNDSMRInfo,不可识别的NDSMR信息类型%d", pMGInfo->infoType ); } }; return; } bool CPlayer::PlayerNDSMRCopyTeamInfoSend() { CMapSrv* pMapsrv = GetMapSrv();//找到mapserver,将相应包转发出去; if ( NULL == pMapsrv ) { D_ERROR( "PlayerNDSMRCopyTeamInfoSend,找不到玩家所在mapsrv\n" ); return false; } //副本信息 unsigned int teamID = 0, playerflag = 0, teamflag =0; GetCopyMapTeamIDInfo( teamID, playerflag, teamflag ); GMSinglePlayerTeamIDNotify srvmsg; srvmsg.upLinePlayerID.wGID = GetPlayerID().wGID; srvmsg.upLinePlayerID.dwPID = GetPlayerID().dwPID; srvmsg.playerFlag = playerflag; srvmsg.teamFlag = teamflag; srvmsg.teamID = teamID; SendMsgToMapSrvByPlayer(GMSinglePlayerTeamIDNotify, this, srvmsg ); D_DEBUG("向地图发送玩家 %s 的副本组队信息 teamFlag:%d , playerFlag:%d\n",this->GetRoleName(), srvmsg.playerFlag, srvmsg.teamFlag ); return true; } ///向Gate发送NDSMR信息; void CPlayer::PlayerNDSMRInfoSend() { CMapSrv* pMapsrv = GetMapSrv();//找到mapserver,将相应包转发出去; if ( NULL == pMapsrv ) { D_ERROR( "PlayerNDSMRInfoSend,找不到玩家所在mapsrv\n" ); return; } //以下依次通知gate各种需要在跳地图过程中保存但又不存盘的信息; GMNDSMRInfo nInfo; nInfo.playerID = GetPlayerID(); MsgToPut* pNewMsg = NULL; //1.跟随怪物的信息; if ( 0!=m_ndsmrInfo.followMonsterType ) { //有跟随怪物; nInfo.infoType = NI_FOLLOW_MONSTER; nInfo.followMonsterType = m_ndsmrInfo.followMonsterType; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } //2 流氓状态的时间 if( 0 != m_ndsmrInfo.rogueTime ) { nInfo.infoType = NI_ROGUE_TIME; nInfo.rogueTime = m_ndsmrInfo.rogueTime; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } //战斗模式 { nInfo.infoType = NI_BATTLE_MODE; nInfo.battleMode = m_ndsmrInfo.battleMode; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } //攻城任务 if( 0 != m_ndsmrInfo.warTaskId ) { nInfo.infoType = NI_WAR_TASK; nInfo.warTaskId = m_ndsmrInfo.warTaskId; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } #ifdef ANTI_ADDICTION if( 0 != m_ndsmrInfo.gameState ) { nInfo.infoType = NI_GAME_STATE; nInfo.gameState = m_ndsmrInfo.gameState; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } #endif /*ANTI_ADDICTION*/ bool isPetValid = ( 0 != (m_ndsmrInfo.petInfo.petInfoInstable.petInfoInstable.petSkillSet & IS_ACTIVATE_MASK) );//( m_petInfoInstable.petInfoInstable.petSkillSet & IS_ACTIVATE_MASK ); if ( isPetValid ) { nInfo.infoType = NI_PET_TIMER; nInfo.petTimer = m_ndsmrInfo.petTimer; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); //注:如果不先发送TIMER信息会有极小概率在PetInfo还没发送过来之前发生定时的轮询导致错误 nInfo.infoType = NI_PET_INFO; StructMemCpy( (nInfo.petInfo), &(m_ndsmrInfo.petInfo), sizeof(nInfo.petInfo) ); //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } //如果有天谴任务 if( m_ndsmrInfo.punishTaskInfo.isHavePunishTask ) { nInfo.infoType = NI_KILL_COUNTER; nInfo.punishTaskInfo = m_ndsmrInfo.punishTaskInfo; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } if(m_ndsmrInfo.anamorphicState > 0) { nInfo.infoType = NI_ANAMORPHIC_STATE; nInfo.anamorphicState = m_ndsmrInfo.anamorphicState; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } if( !m_ndsmrInfo.storageLock ) { nInfo.infoType = NI_STORAGE_INFO; nInfo.storageLock = m_ndsmrInfo.storageLock; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } if( m_ndsmrInfo.rookieBreakTime != 0 ) { nInfo.rookieBreakTime = m_ndsmrInfo.rookieBreakTime; nInfo.infoType = NI_ROOKIE_BREAK_TIME; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } if( m_ndsmrInfo.tpBuffData.buffArrSize != 0 ) { nInfo.tpBuffData = m_ndsmrInfo.tpBuffData; nInfo.infoType = NI_BUFF_DATA; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } if( m_ndsmrInfo.killInfo.killCount != 0 ) { nInfo.infoType = NI_KILL_INFO; nInfo.killInfo = m_ndsmrInfo.killInfo; //pNewMsg = CreateSrvPkg( GMNDSMRInfo, pMapsrv, nInfo ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMNDSMRInfo, pMapsrv, nInfo ); } //每次都清空NDSMR信息(只有mapsrv发来,然后跳地图时用一次,每次新跳地图都会有新的mapsrv消息事先更新); ClearNDSMRInfo(); return; } bool CPlayer::QueryUnionInfo(void) { TRY_BEGIN QueryUnionBasicRequest srvmsg; StructMemSet( srvmsg, 0x00, sizeof(srvmsg) ); srvmsg.uiid = GetSeledRole(); SendMsgToRelationSrv(QueryUnionBasicRequest, srvmsg); return true; TRY_END; return false; } void CPlayer::GMAccountNotify(void) { if(IsGMAccount()) { CMapSrv* pMapsrv = GetMapSrv(); if ( NULL == pMapsrv ) { D_ERROR( "GMAccountNotify,找不到玩家所在mapsrv\n" ); return; } GMGMAccountNtf srvmsg; srvmsg.notiPlayerID = GetPlayerID(); //MsgToPut* pNewMsg = CreateSrvPkg( GMGMAccountNtf, pMapsrv, srvmsg ); //pMapsrv->SendPkgToSrv( pNewMsg ); SendMsgToSrv( GMGMAccountNtf, pMapsrv, srvmsg ); } return; } #ifdef ANTI_ADDICTION bool CPlayer::SendGameState() //当游戏状态改变时向mapsrv发送防沉迷的状态 { GMGameStateNotify mapMsg; mapMsg.state = m_ndsmrInfo.gameState; mapMsg.lNotiPlayerID = GetPlayerID(); SendMsgToMapSrvByPlayer( GMGameStateNotify, this, mapMsg ); return true; } void CPlayer::SetGameState( UINT state) //保存当前的游戏状态 { m_ndsmrInfo.gameState = state; } UINT CPlayer::GetGameState() { return m_ndsmrInfo.gameState; } #endif /*ANTI_ADDICTION*/