首页 > 代码库 > 玩家下线(GS部分)
玩家下线(GS部分)
玩家下线,之前一直感觉这个过程有点复杂else if (stat == link_stat::link_disconnected || stat == link_stat::link_connect_failed ){ GameChannel* pDisconnectGC = m_vecChannel[rPkt.channel_id]; if(pDisconnectGC) { //如果进入了地图,保存人物信息时会调用push_freeQueue + 滞空m_Channels[channel_id], pDisconnectGC->OnDisconnect();//下线的一些收尾工作 //如果未进地图就下线,直接断开;不用保存角色详细数据,可直接放入释放队列中 if(!pDisconnectGC->m_pMap) { //PushFreeQueue(pDisconnectGC); //m_vecChannel[rPkt.channel_id] = NULL; AutoFreeGC(pDisconnectGC); } } m_LiveMgr.Remove(rPkt.channel_id);//将livemgr的这个位置清零}下面一步一步看这个过程bool GameChannel::OnDisconnect(){ //m_isDisconnect = true; OnOffLine(); return true;}void GameChannel::OnOffLine(){ switch (m_eGameState) { case eGameState_Login://登录状态 ClearLoginRcd();//清除登录状态:主要是删除已删除的角色,删除在线用户 break; case eGameState_EnterMap://进入地图状态 ClearMapRcd();//从map下线,这个获取后面看 ClearLoginRcd();//清除登录状态 break; case eGameState_InChangeMap: //...正在切图就下线了,是不是该延时下线呢? m_eGameState = eGameState_DelayDisconnect; case eGameState_OnlyConnect: //未登陆,空连接 case eGameState_Disconnect: //已离线 return; default: break; } m_eGameState = eGameState_Disconnect;//将状态切换成离线状态}void GameServer::AutoFreeGC(GameChannel* pGameChannel){ m_vecChannel[pGameChannel->m_nChannelId] = NULL; //channel里面有个m_uDBGetAskRefCount,由于判断数据库是否有返回,加入数据库很慢的时候玩家下线你把这个内存释放了,等数据库返回的时候就访问了野指针 if (pGameChannel->IsNoDBAsk())//没有数据库访问,可以安全的删除指针了 { delete pGameChannel;//删除玩家指针 pGameChannel = nullptr; } else { PushFreeQueue(pGameChannel);//如果还有数据库访问,就将其放到释放队列中延迟释放 }}void GameServer::PushFreeQueue(GameChannel* gc){ FreeChannel fch; fch.m_pGameChannel = gc; fch.m_uTime = GetTickCount(); m_FreeQueue.push(fch);}//那这个队列到底什么时候释放的呢?在主线程里面初始化了一个定时器void GameServer::InitTimer(){ I_TimerFactory* pTimeFactory = NEW(TimerFactory); SetPlug("TimerFactory", pTimeFactory); m_FreeQueueTimer.reset(pTimeFactory->createTimer()); m_FreeQueueTimer->regTimer(std::bind(&GameServer::FreeQueueTimer, this)); m_FreeQueueTimer->setInterval(30 * 1000);//(30 * 1000); m_FreeQueueTimer->start();}//之前出现过,函数回调的时候出现错误,当时就是这个问题回调的时候玩家已经下线了,channel已经删除了/** * 方案一:不直接释放,延迟1分钟,保证数据库不再返回时再释放。(数据库太忙情况不安全,停用) * 方案二:不直接释放,看GC标志是否无数据请求。 */void GameServer::FreeQueueTimer(){ if(!m_FreeQueue.size()) return ; int now = GetTickCount(); for (;;)//每次释放完或者到有不能释放的为止 { if(!m_FreeQueue.size()) return ; FreeChannel tmpFreeChannel = m_FreeQueue.front(); //if(now - tmpFreeChannel.m_uTime > 60 * 1000) if (tmpFreeChannel.m_pGameChannel->IsNoDBAsk())//等到数据库没有访问了再释放 { delete tmpFreeChannel.m_pGameChannel; m_FreeQueue.pop(); } else { break; } }}
玩家下线(GS部分)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。