From d6138f01a6a14cc069ce47856d1d828af0fb2d7a Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sat, 19 Jun 2010 05:52:17 +0400 Subject: [PATCH] [10077] Add delayed far teleports for opcode handlers Some opcode handlers have many code with possible deep calling far teleports by some reason (death, quest script, etc). This can be triggering unexpected lost Map context and crashs result. Note: player login opcode still have disbled delayed teleports (old way work) just becase Player object created in it and not have flag set. Calling point look not 100% safe but at this commit this way not chnages for while. --- src/game/CharacterHandler.cpp | 1 + src/game/WorldSession.cpp | 47 +++++++++++++++++++++-------------- src/game/WorldSession.h | 4 +++ src/shared/revision_nr.h | 2 +- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index 8357ede9e..5e4e2421b 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -703,6 +703,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder *holder) if (!pCurrChar->GetMap()->Add(pCurrChar)) { + // normal delayed teleport protection not applied (and this correct) for this case (Player object just created) AreaTrigger const* at = sObjectMgr.GetGoBackTrigger(pCurrChar->GetMapId()); if(at) pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation()); diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index 273cf088e..491de312c 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -184,11 +184,8 @@ bool WorldSession::Update(uint32 /*diff*/) LogUnexpectedOpcode(packet, "the player has not logged in yet"); } else if(_player->IsInWorld()) - { - (this->*opHandle.handler)(*packet); - if (packet->rpos() < packet->wpos() && sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) - LogUnprocessedTail(packet); - } + ExecuteOpcode(opHandle, packet); + // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGEDOUT: @@ -197,12 +194,8 @@ bool WorldSession::Update(uint32 /*diff*/) LogUnexpectedOpcode(packet, "the player has not logged in yet and not recently logout"); } else - { // not expected _player or must checked in packet hanlder - (this->*opHandle.handler)(*packet); - if (packet->rpos() < packet->wpos() && sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) - LogUnprocessedTail(packet); - } + ExecuteOpcode(opHandle, packet); break; case STATUS_TRANSFER: if(!_player) @@ -210,11 +203,7 @@ bool WorldSession::Update(uint32 /*diff*/) else if(_player->IsInWorld()) LogUnexpectedOpcode(packet, "the player is still in world"); else - { - (this->*opHandle.handler)(*packet); - if (packet->rpos() < packet->wpos() && sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) - LogUnprocessedTail(packet); - } + ExecuteOpcode(opHandle, packet); break; case STATUS_AUTHED: // prevent cheating with skip queue wait @@ -229,9 +218,7 @@ bool WorldSession::Update(uint32 /*diff*/) if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) m_playerRecentlyLogout = false; - (this->*opHandle.handler)(*packet); - if (packet->rpos() < packet->wpos() && sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) - LogUnprocessedTail(packet); + ExecuteOpcode(opHandle, packet); break; case STATUS_NEVER: sLog.outError( "SESSION: received not allowed opcode %s (0x%.4X)", @@ -872,3 +859,27 @@ void WorldSession::SendRedirectClient(std::string& ip, uint16 port) SendPacket(&pkt); } + +void WorldSession::ExecuteOpcode( OpcodeHandler& opHandle, WorldPacket* packet ) +{ + // need prevent do internal far teleports in handlers because some handlers do lot steps + // or call code that can do far teleports in some conditions unexpectedly for generic way work code + if (_player) + _player->SetCanDelayTeleport(true); + + (this->*opHandle.handler)(*packet); + + if (_player) + { + // can be not set in fact for login opcode, but this not create porblems. + _player->SetCanDelayTeleport(false); + + //we should execute delayed teleports only for alive(!) players + //because we don't want player's ghost teleported from graveyard + if (_player->IsHasDelayedTeleport() && _player->isAlive()) + _player->TeleportTo(_player->m_teleport_dest, _player->m_teleport_options); + } + + if (packet->rpos() < packet->wpos() && sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) + LogUnprocessedTail(packet); +} \ No newline at end of file diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index 8aa6ba959..23ae01646 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -43,6 +43,8 @@ class LoginQueryHolder; class CharacterHandler; class GMTicket; +struct OpcodeHandler; + enum AccountDataType { GLOBAL_CONFIG_CACHE = 0, // 0x01 g @@ -773,6 +775,8 @@ class MANGOS_DLL_SPEC WorldSession // private trade methods void moveItems(Item* myItems[], Item* hisItems[]); + void ExecuteOpcode( OpcodeHandler& opHandle, WorldPacket* packet ); + // logging helper void LogUnexpectedOpcode(WorldPacket *packet, const char * reason); void LogUnprocessedTail(WorldPacket *packet); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index c40f920e0..a6b664f8b 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10076" + #define REVISION_NR "10077" #endif // __REVISION_NR_H__