Exemple #1
0
void SocketHandler::SendPacket(const WorldPacket& data) const
{
    m_socket->write(data.GetPacket().toLatin1() + (char)0x00);
    Log::Write(LOG_TYPE_DEBUG, "Send packet %s ( Header : %s )", GetOpcodeName(data.GetOpcode()).toLatin1().data(), GetOpcodeHeader(data.GetOpcode()).toLatin1().data());
    if(data.GetPacket().length() > 0)
        Log::Write(LOG_TYPE_DEBUG, "Packet data : %s", QString(data.GetPacket()).toLatin1().data());
}
Exemple #2
0
/// Update the WorldSession (triggered by World update)
bool WorldSession::Update(PacketFilter& updater)
{
    std::lock_guard<std::mutex> guard(m_recvQueueLock);

    ///- Retrieve packets from the receive queue and call the appropriate handlers
    /// not process packets if socket already closed
    while (m_Socket && !m_Socket->IsClosed() && !m_recvQueue.empty())
    {
        auto const packet = std::move(m_recvQueue.front());
        m_recvQueue.pop_front();

        /*#if 1
        sLog.outError( "MOEP: %s (0x%.4X)",
                        packet->GetOpcodeName(),
                        packet->GetOpcode());
        #endif*/

        OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()];
        try
        {
            switch (opHandle.status)
            {
                case STATUS_LOGGEDIN:
                    if (!_player)
                    {
                        // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
                        if (!m_playerRecentlyLogout)
                            LogUnexpectedOpcode(*packet, "the player has not logged in yet");
                    }
                    else if (_player->IsInWorld())
                        ExecuteOpcode(opHandle, *packet);

                    // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
                    break;
                case STATUS_LOGGEDIN_OR_RECENTLY_LOGGEDOUT:
                    if (!_player && !m_playerRecentlyLogout)
                    {
                        LogUnexpectedOpcode(*packet, "the player has not logged in yet and not recently logout");
                    }
                    else
                        // not expected _player or must checked in packet hanlder
                        ExecuteOpcode(opHandle, *packet);
                    break;
                case STATUS_TRANSFER:
                    if (!_player)
                        LogUnexpectedOpcode(*packet, "the player has not logged in yet");
                    else if (_player->IsInWorld())
                        LogUnexpectedOpcode(*packet, "the player is still in world");
                    else
                        ExecuteOpcode(opHandle, *packet);
                    break;
                case STATUS_AUTHED:
                    // prevent cheating with skip queue wait
                    if (m_inQueue)
                    {
                        LogUnexpectedOpcode(*packet, "the player not pass queue yet");
                        break;
                    }

                    // single from authed time opcodes send in to after logout time
                    // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes.
                    if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL)
                        m_playerRecentlyLogout = false;

                    ExecuteOpcode(opHandle, *packet);
                    break;
                case STATUS_NEVER:
                    sLog.outError("SESSION: received not allowed opcode %s (0x%.4X)",
                                  packet->GetOpcodeName(),
                                  packet->GetOpcode());
                    break;
                case STATUS_UNHANDLED:
                    DEBUG_LOG("SESSION: received not handled opcode %s (0x%.4X)",
                              packet->GetOpcodeName(),
                              packet->GetOpcode());
                    break;
                default:
                    sLog.outError("SESSION: received wrong-status-req opcode %s (0x%.4X)",
                                  packet->GetOpcodeName(),
                                  packet->GetOpcode());
                    break;
            }
        }
        catch (ByteBufferException&)
        {
            sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i.",
                          packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
            if (sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG))
            {
                DEBUG_LOG("Dumping error causing packet:");
                packet->hexlike();
            }

            if (sWorld.getConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET))
            {
                DETAIL_LOG("Disconnecting session [account id %u / address %s] for badly formatted packet.",
                           GetAccountId(), GetRemoteAddress().c_str());

                KickPlayer();
            }
        }
    }

    // check if we are safe to proceed with logout
    // logout procedure should happen only in World::UpdateSessions() method!!!
    if (updater.ProcessLogout())
    {
        ///- If necessary, log the player out
        const time_t currTime = time(nullptr);

        if (m_Socket->IsClosed() || (ShouldLogOut(currTime) && !m_playerLoading))
            LogoutPlayer(true);

        // finalize the session if disconnected.
        if (m_Socket->IsClosed())
            return false;
    }

    return true;
}
//Returns -1 if this thread is dead and needs to be killed
int CCobThread::Tick(int deltaTime)
{
	if (state == Sleep) {
		logOutput.Print("CobError: sleeping thread ticked!");
	}
	if (state == Dead || !owner) {
		return -1;
	}

	state = Run;
	GCobEngine.SetCurThread(this);

	int r1, r2, r3, r4, r5, r6;
	vector<int> args;
	CCobThread *thread;

	execTrace.clear();
	delayedAnims.clear();
	//list<int>::iterator ei;
	vector<int>::iterator ei;

#if COB_DEBUG > 0
	if (COB_DEBUG_FILTER)
		logOutput.Print("Executing in %s (from %s)", script.scriptNames[callStack.back().functionId].c_str(), GetName().c_str());
#endif

	while (state == Run) {
		//int opcode = *(int *)&script.code[PC];

		//Disabling exec trace gives about a 50% speedup on vm-intensive code
		//execTrace.push_back(PC);

		int opcode = GET_LONG_PC();

#if COB_DEBUG > 1
		if (COB_DEBUG_FILTER)
			logOutput.Print("PC: %x opcode: %x (%s)", PC - 1, opcode, GetOpcodeName(opcode).c_str());
#endif

		switch(opcode) {
			case PUSH_CONSTANT:
				r1 = GET_LONG_PC();
				stack.push_back(r1);
				break;
			case SLEEP:
				r1 = POP();
				wakeTime = GCurrentTime + r1;
				state = Sleep;
				GCobEngine.AddThread(this);
				GCobEngine.SetCurThread(NULL);

#if COB_DEBUG > 0
				if (COB_DEBUG_FILTER)
					logOutput.Print("%s sleeping for %d ms", script.scriptNames[callStack.back().functionId].c_str(), r1);
#endif
				return 0;
			case SPIN:
				r1 = GET_LONG_PC();
				r2 = GET_LONG_PC();
				r3 = POP();				//speed
				r4 = POP();				//accel
				owner->Spin(r1, r2, r3, r4);
				break;
			case STOP_SPIN:
				r1 = GET_LONG_PC();
				r2 = GET_LONG_PC();
				r3 = POP();				//decel
				//logOutput.Print("Stop spin of %s around %d", script.pieceNames[r1].c_str(), r2);
				owner->StopSpin(r1, r2, r3);
				break;
			case RETURN:
				retCode = POP();
				if (callStack.back().returnAddr == -1) {

#if COB_DEBUG > 0
					if (COB_DEBUG_FILTER)
						logOutput.Print("%s returned %d", script.scriptNames[callStack.back().functionId].c_str(), retCode);
#endif

					state = Dead;
					GCobEngine.SetCurThread(NULL);
					//callStack.pop_back();
					//Leave values intact on stack in case caller wants to check them
					return -1;
				}

				PC = callStack.back().returnAddr;
				while (stack.size() > callStack.back().stackTop) {
					stack.pop_back();
				}
				callStack.pop_back();

#if COB_DEBUG > 0
				if (COB_DEBUG_FILTER)
					logOutput.Print("Returning to %s", script.scriptNames[callStack.back().functionId].c_str());
#endif

				break;
			case SHADE:
				r1 = GET_LONG_PC();
				break;
			case DONT_SHADE:
				r1 = GET_LONG_PC();
				break;
			case CACHE:
				r1 = GET_LONG_PC();
				break;
			case DONT_CACHE:
				r1 = GET_LONG_PC();
				break;
			case CALL: {
				r1 = GET_LONG_PC();
				PC--;
				const string& name = script.scriptNames[r1];
				if (name.find("lua_") == 0) {
					script.code[PC - 1] = LUA_CALL;
					LuaCall();
					break;
				}
				script.code[PC - 1] = REAL_CALL;

				// fall through //
			}
			case REAL_CALL:
				r1 = GET_LONG_PC();
				r2 = GET_LONG_PC();

				if (script.scriptLengths[r1] == 0) {
					//logOutput.Print("Preventing call to zero-len script %s", script.scriptNames[r1].c_str());
					break;
				}

				struct callInfo ci;
				ci.functionId = r1;
				ci.returnAddr = PC;
				ci.stackTop = stack.size() - r2;
				callStack.push_back(ci);
				paramCount = r2;

				PC = script.scriptOffsets[r1];
#if COB_DEBUG > 0
				if (COB_DEBUG_FILTER)
					logOutput.Print("Calling %s", script.scriptNames[r1].c_str());
#endif
				break;
			case LUA_CALL:
				LuaCall();
				break;
			case POP_STATIC:
				r1 = GET_LONG_PC();
				r2 = POP();
				owner->staticVars[r1] = r2;
				//logOutput.Print("Pop static var %d val %d", r1, r2);
				break;
			case POP_STACK:
				POP();
				break;
			case START:
				r1 = GET_LONG_PC();
				r2 = GET_LONG_PC();

				if (script.scriptLengths[r1] == 0) {
					//logOutput.Print("Preventing start of zero-len script %s", script.scriptNames[r1].c_str());
					break;
				}

				args.clear();
				for (r3 = 0; r3 < r2; ++r3) {
					r4 = POP();
					args.push_back(r4);
				}

				thread = SAFE_NEW CCobThread(script, owner);
				thread->Start(r1, args, true);

				//Seems that threads should inherit signal mask from creator
				thread->signalMask = signalMask;

#if COB_DEBUG > 0
				if (COB_DEBUG_FILTER)
					logOutput.Print("Starting %s %d", script.scriptNames[r1].c_str(), signalMask);
#endif

				break;
			case CREATE_LOCAL_VAR:
				if (paramCount == 0) {
					stack.push_back(0);
				}
				else {
					paramCount--;
				}
				break;
			case GET_UNIT_VALUE:
				r1 = POP();
				if ((r1 >= LUA0) && (r1 <= LUA9)) {
					stack.push_back(luaArgs[r1 - LUA0]);
					break;
				}
				ForceCommitAllAnims();			// getunitval could possibly read piece locations
				r1 = owner->GetUnitVal(r1, 0, 0, 0, 0);
				stack.push_back(r1);
				break;
			case JUMP_NOT_EQUAL:
				r1 = GET_LONG_PC();
				r2 = POP();
				if (r2 == 0) {
					PC = r1;
				}
				break;
			case JUMP:
				r1 = GET_LONG_PC();
				//this seem to be an error in the docs..
				//r2 = script.scriptOffsets[callStack.back().functionId] + r1;
				PC = r1;
				break;
			case POP_LOCAL_VAR:
				r1 = GET_LONG_PC();
				r2 = POP();
				stack[callStack.back().stackTop + r1] = r2;
				break;
			case PUSH_LOCAL_VAR:
				r1 = GET_LONG_PC();
				r2 = stack[callStack.back().stackTop + r1];
				stack.push_back(r2);
				break;
			case SET_LESS_OR_EQUAL:
				r2 = POP();
				r1 = POP();
				if (r1 <= r2)
					stack.push_back(1);
				else
					stack.push_back(0);
				break;
			case BITWISE_AND:
				r1 = POP();
				r2 = POP();
				stack.push_back(r1 & r2);
				break;
			case BITWISE_OR:	//seems to want stack contents or'd, result places on stack
				r1 = POP();
				r2 = POP();
				stack.push_back(r1 | r2);
				break;
			case BITWISE_XOR:
				r1 = POP();
				r2 = POP();
				stack.push_back(r1 ^ r2);
				break;
			case BITWISE_NOT:
				r1 = POP();
				stack.push_back(~r1);
				break;
			case EXPLODE:
				r1 = GET_LONG_PC();
				r2 = POP();
				owner->Explode(r1, r2);
				break;
			case PLAY_SOUND:
				r1 = GET_LONG_PC();
				r2 = POP();
				owner->PlayUnitSound(r1, r2);
				break;
			case PUSH_STATIC:
				r1 = GET_LONG_PC();
				stack.push_back(owner->staticVars[r1]);
				//logOutput.Print("Push static %d val %d", r1, owner->staticVars[r1]);
				break;
			case SET_NOT_EQUAL:
				r1 = POP();
				r2 = POP();
				if (r1 != r2)
					stack.push_back(1);
				else
					stack.push_back(0);
				break;
			case SET_EQUAL:
				r1 = POP();
				r2 = POP();
				if (r1 == r2)
					stack.push_back(1);
				else
					stack.push_back(0);
				break;
			case SET_LESS:
				r2 = POP();
				r1 = POP();
				if (r1 < r2)
					stack.push_back(1);
				else
					stack.push_back(0);
				break;
			case SET_GREATER:
				r2 = POP();
				r1 = POP();
				if (r1 > r2)
					stack.push_back(1);
				else
					stack.push_back(0);
				break;
			case SET_GREATER_OR_EQUAL:
				r2 = POP();
				r1 = POP();
				if (r1 >= r2)
					stack.push_back(1);
				else
					stack.push_back(0);
				break;
			case RAND:
				r2 = POP();
				r1 = POP();
				r3 = gs->randInt() % (r2 - r1 + 1) + r1;
				stack.push_back(r3);
				break;
			case EMIT_SFX:
				r1 = POP();
				r2 = GET_LONG_PC();
				owner->EmitSfx(r1, r2);
				break;
			case MUL:
				r1 = POP();
				r2 = POP();
				stack.push_back(r1 * r2);
				break;
			case SIGNAL:
				r1 = POP();
				owner->Signal(r1);
				break;
			case SET_SIGNAL_MASK:
				r1 = POP();
				signalMask = r1;
				break;
			case TURN:
				r2 = POP();
				r1 = POP();
				r3 = GET_LONG_PC();
				r4 = GET_LONG_PC();
				//logOutput.Print("Turning piece %s axis %d to %d speed %d", script.pieceNames[r3].c_str(), r4, r2, r1);
				ForceCommitAnim(1, r3, r4);
				owner->Turn(r3, r4, r1, r2);
				break;
			case GET:
				r5 = POP();
				r4 = POP();
				r3 = POP();
				r2 = POP();
				r1 = POP();
				if ((r1 >= LUA0) && (r1 <= LUA9)) {
					stack.push_back(luaArgs[r1 - LUA0]);
					break;
				}
				ForceCommitAllAnims();
				r6 = owner->GetUnitVal(r1, r2, r3, r4, r5);
				stack.push_back(r6);
				break;
			case ADD:
				r2 = POP();
				r1 = POP();
				stack.push_back(r1 + r2);
				break;
			case SUB:
				r2 = POP();
				r1 = POP();
				r3 = r1 - r2;
				stack.push_back(r3);
				break;
			case DIV:
				r2 = POP();
				r1 = POP();
				if (r2 != 0)
					r3 = r1 / r2;
				else {
					r3 = 1000;	//infinity!
					logOutput.Print("CobError: division by zero");
				}
				stack.push_back(r3);
				break;
			case MOD:
				r2 = POP();
				r1 = POP();
				if (r2 != 0)
					stack.push_back(r1 % r2);
				else {
					stack.push_back(0);
					logOutput.Print("CobError: modulo division by zero");
				}
				break;
			case MOVE:
				r1 = GET_LONG_PC();
				r2 = GET_LONG_PC();
				r4 = POP();
				r3 = POP();
				ForceCommitAnim(2, r1, r2);
				owner->Move(r1, r2, r3, r4);
				break;
			case MOVE_NOW:{
				r1 = GET_LONG_PC();
				r2 = GET_LONG_PC();
				r3 = POP();

				if (owner->smoothAnim) {
					DelayedAnim a;
					a.type = 2;
					a.piece = r1;
					a.axis = r2;
					a.dest = r3;
					delayedAnims.push_back(a);

					//logOutput.Print("Delayed move %s %d %d", owner->pieces[r1].name.c_str(), r2, r3);
				}
				else {
					owner->MoveNow(r1, r2, r3);
				}

				break;}
			case TURN_NOW:{
				r1 = GET_LONG_PC();
				r2 = GET_LONG_PC();
				r3 = POP();

				if (owner->smoothAnim) {
					DelayedAnim a;
					a.type = 1;
					a.piece = r1;
					a.axis = r2;
					a.dest = r3;
					delayedAnims.push_back(a);
				}
				else {
					owner->TurnNow(r1, r2, r3);
				}

				break;}
			case WAIT_TURN:
				r1 = GET_LONG_PC();
				r2 = GET_LONG_PC();
				//logOutput.Print("Waiting for turn on piece %s around axis %d", script.pieceNames[r1].c_str(), r2);
				if (owner->AddTurnListener(r1, r2, this)) {
					state = WaitTurn;
					GCobEngine.SetCurThread(NULL);
					return 0;
				}
				else
					break;
			case WAIT_MOVE:
				r1 = GET_LONG_PC();
				r2 = GET_LONG_PC();
				//logOutput.Print("Waiting for move on piece %s on axis %d", script.pieceNames[r1].c_str(), r2);
				if (owner->AddMoveListener(r1, r2, this)) {
					state = WaitMove;
					GCobEngine.SetCurThread(NULL);
					return 0;
				}
				break;
			case SET:
				r2 = POP();
				r1 = POP();
				//logOutput.Print("Setting unit value %d to %d", r1, r2);
				if ((r1 >= LUA0) && (r1 <= LUA9)) {
					luaArgs[r1 - LUA0] = r2;
					break;
				}
				owner->SetUnitVal(r1, r2);
				break;
			case ATTACH:
				r3 = POP();
				r2 = POP();
				r1 = POP();
				owner->AttachUnit(r2, r1);
				break;
			case DROP:
				r1 = POP();
				owner->DropUnit(r1);
				break;
			case LOGICAL_NOT:		//Like bitwise, but only on values 1 and 0.
				r1 = POP();
				if (r1 == 0)
					stack.push_back(1);
				else
					stack.push_back(0);
				break;
			case LOGICAL_AND:
				r1 = POP();
				r2 = POP();
				if (r1 && r2)
					stack.push_back(1);
				else
					stack.push_back(0);
				break;
			case LOGICAL_OR:
				r1 = POP();
				r2 = POP();
				if (r1 || r2)
					stack.push_back(1);
				else
					stack.push_back(0);
				break;
			case LOGICAL_XOR:
				r1 = POP();
				r2 = POP();
				if (!!r1 ^ !!r2)
					stack.push_back(1);
				else
					stack.push_back(0);
				break;
			case HIDE:
				r1 = GET_LONG_PC();
				owner->SetVisibility(r1, false);
				//logOutput.Print("Hiding %d", r1);
				break;
			case SHOW:{
				r1 = GET_LONG_PC();
				int i;
				for (i = 0; i < COB_MaxWeapons; ++i)
					if (callStack.back().functionId == script.scriptIndex[COBFN_FirePrimary + i])
						break;

				// If true, we are in a Fire-script and should show a special flare effect
				if (i < COB_MaxWeapons) {
					owner->ShowFlare(r1);
				}
				else {
					owner->SetVisibility(r1, true);
				}
				//logOutput.Print("Showing %d", r1);
				break;}
			default:
				logOutput.Print("CobError: Unknown opcode %x (in %s:%s at %x)", opcode, script.name.c_str(), script.scriptNames[callStack.back().functionId].c_str(), PC - 1);
				logOutput.Print("Exec trace:");
				ei = execTrace.begin();
				while (ei != execTrace.end()) {
					logOutput.Print("PC: %3x  opcode: %s", *ei, GetOpcodeName(script.code[*ei]).c_str());
					ei++;
				}
				state = Dead;
				GCobEngine.SetCurThread(NULL);
				return -1;
				break;
		}

	}

	GCobEngine.SetCurThread(NULL);
	return 0;
}
/// Update the WorldSession (triggered by World update)
bool WorldSession::Update(PacketFilter& updater)
{
    std::lock_guard<std::mutex> guard(m_recvQueueLock);

    ///- Retrieve packets from the receive queue and call the appropriate handlers
    /// not process packets if socket already closed
    while (m_Socket && !m_Socket->IsClosed() && !m_recvQueue.empty())
    {
        auto const packet = std::move(m_recvQueue.front());
        m_recvQueue.pop_front();

        /*#if 1
        sLog.outError( "MOEP: %s (0x%.4X)",
                        packet->GetOpcodeName(),
                        packet->GetOpcode());
        #endif*/

        OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()];
        try
        {
            switch (opHandle.status)
            {
                case STATUS_LOGGEDIN:
                    if (!_player)
                    {
                        // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
                        if (!m_playerRecentlyLogout)
                            LogUnexpectedOpcode(*packet, "the player has not logged in yet");
                    }
                    else if (_player->IsInWorld())
                        ExecuteOpcode(opHandle, *packet);

                    // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer

#ifdef BUILD_PLAYERBOT
                    if (_player && _player->GetPlayerbotMgr())
                        _player->GetPlayerbotMgr()->HandleMasterIncomingPacket(*packet);
#endif
                    break;
                case STATUS_LOGGEDIN_OR_RECENTLY_LOGGEDOUT:
                    if (!_player && !m_playerRecentlyLogout)
                    {
                        LogUnexpectedOpcode(*packet, "the player has not logged in yet and not recently logout");
                    }
                    else
                        // not expected _player or must checked in packet hanlder
                        ExecuteOpcode(opHandle, *packet);
                    break;
                case STATUS_TRANSFER:
                    if (!_player)
                        LogUnexpectedOpcode(*packet, "the player has not logged in yet");
                    else if (_player->IsInWorld())
                        LogUnexpectedOpcode(*packet, "the player is still in world");
                    else
                        ExecuteOpcode(opHandle, *packet);
                    break;
                case STATUS_AUTHED:
                    // prevent cheating with skip queue wait
                    if (m_inQueue)
                    {
                        LogUnexpectedOpcode(*packet, "the player not pass queue yet");
                        break;
                    }

                    // single from authed time opcodes send in to after logout time
                    // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes.
                    if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL)
                        m_playerRecentlyLogout = false;

                    ExecuteOpcode(opHandle, *packet);
                    break;
                case STATUS_NEVER:
                    sLog.outError("SESSION: received not allowed opcode %s (0x%.4X)",
                                  packet->GetOpcodeName(),
                                  packet->GetOpcode());
                    break;
                case STATUS_UNHANDLED:
                    DEBUG_LOG("SESSION: received not handled opcode %s (0x%.4X)",
                              packet->GetOpcodeName(),
                              packet->GetOpcode());
                    break;
                default:
                    sLog.outError("SESSION: received wrong-status-req opcode %s (0x%.4X)",
                                  packet->GetOpcodeName(),
                                  packet->GetOpcode());
                    break;
            }
        }
        catch (ByteBufferException&)
        {
            sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i.",
                          packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
            if (sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG))
            {
                DEBUG_LOG("Dumping error causing packet:");
                packet->hexlike();
            }

            if (sWorld.getConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET))
            {
                DETAIL_LOG("Disconnecting session [account id %u / address %s] for badly formatted packet.",
                           GetAccountId(), GetRemoteAddress().c_str());

                KickPlayer();
            }
        }
    }

#ifdef BUILD_PLAYERBOT
    // Process player bot packets
    // The PlayerbotAI class adds to the packet queue to simulate a real player
    // since Playerbots are known to the World obj only by its master's WorldSession object
    // we need to process all master's bot's packets.
    if (GetPlayer() && GetPlayer()->GetPlayerbotMgr())
    {
        for (PlayerBotMap::const_iterator itr = GetPlayer()->GetPlayerbotMgr()->GetPlayerBotsBegin();
                itr != GetPlayer()->GetPlayerbotMgr()->GetPlayerBotsEnd(); ++itr)
        {
            Player* const botPlayer = itr->second;
            WorldSession* const pBotWorldSession = botPlayer->GetSession();
            if (botPlayer->IsBeingTeleported())
                botPlayer->GetPlayerbotAI()->HandleTeleportAck();
            else if (botPlayer->IsInWorld())
            {
                while (!pBotWorldSession->m_recvQueue.empty())
                {
                    auto const botpacket = std::move(pBotWorldSession->m_recvQueue.front());
                    pBotWorldSession->m_recvQueue.pop_front();

                    OpcodeHandler const& opHandle = opcodeTable[botpacket->GetOpcode()];
                    pBotWorldSession->ExecuteOpcode(opHandle, *botpacket);
                };
                pBotWorldSession->m_recvQueue.clear();
            }
        }
    }
#endif

    // check if we are safe to proceed with logout
    // logout procedure should happen only in World::UpdateSessions() method!!!
    if (updater.ProcessLogout())
    {
        switch (m_sessionState)
        {
            case WORLD_SESSION_STATE_CREATED:
            {
                if (m_requestSocket)
                {
                    if (!IsOffline())
                        SetOffline();

                    m_Socket = m_requestSocket;
                    m_requestSocket = nullptr;
                    sLog.outString("New Session key %s", m_Socket->GetSessionKey().AsHexStr());
                    SendAuthOk();
                }
                else
                {
                    if (m_inQueue)
                        SendAuthQueued();
                    else
                        SendAuthOk();
                }
                m_sessionState = WORLD_SESSION_STATE_CHAR_SELECTION;
                return true;
            }

            case WORLD_SESSION_STATE_CHAR_SELECTION:

                // waiting to go online
                // TODO:: Maybe check if have to send queue update?
                if (!m_Socket || (m_Socket && m_Socket->IsClosed()))
                {
                    // directly remove this session
                    return false;
                }

                if (ShouldLogOut(time(nullptr)) && !m_playerLoading)   // check if delayed logout is fired
                    LogoutPlayer(true);

                return true;

            case WORLD_SESSION_STATE_READY:
            {
                if (m_Socket && m_Socket->IsClosed())
                {
                    if (!_player)
                        return false;

                    // give the opportunity for this player to reconnect within 20 sec
                    SetOffline();
                }
                else if (ShouldLogOut(time(nullptr)) && !m_playerLoading)   // check if delayed logout is fired
                    LogoutPlayer(true);

                return true;
            }

            case WORLD_SESSION_STATE_OFFLINE:
            {
                if (ShouldDisconnect(time(nullptr)))   // check if delayed logout is fired
                {
                    LogoutPlayer(true);
                    if (!m_requestSocket && (!m_Socket || m_Socket->IsClosed()))
                        return false;
                }

                return true;
            }
            default:
                break;
        }
    }

    return true;
}