首页 > 代码库 > 玩家下线(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部分)