aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormegamage <none@none>2009-07-01 18:36:03 -0500
committermegamage <none@none>2009-07-01 18:36:03 -0500
commit4a8a89e1db1f103020ffecbb570e1c570c2e0d21 (patch)
treed5e62fa664a0f36d668f738abc50ac9406d50e5a /src
parent111dac5f94eac3fe26da2107842dea4e1aacd660 (diff)
[8103] More wide use IsInWorld checks and delayed at teleport operations. Author: Ambal
* IsInWorld used to prevent return unexpected not in world objects. * Delayed operations need to process its in world state. --HG-- branch : trunk
Diffstat (limited to 'src')
-rw-r--r--src/game/AccountMgr.cpp2
-rw-r--r--src/game/AchievementMgr.cpp5
-rw-r--r--src/game/GameObject.cpp8
-rw-r--r--src/game/Group.cpp2
-rw-r--r--src/game/LFGHandler.cpp10
-rw-r--r--src/game/MiscHandler.cpp4
-rw-r--r--src/game/MovementHandler.cpp6
-rw-r--r--src/game/NPCHandler.cpp4
-rw-r--r--src/game/ObjectAccessor.cpp10
-rw-r--r--src/game/ObjectAccessor.h10
-rw-r--r--src/game/PetHandler.cpp3
-rw-r--r--src/game/Player.cpp133
-rw-r--r--src/game/Player.h21
-rw-r--r--src/game/Unit.cpp2
-rw-r--r--src/game/WorldSession.cpp6
15 files changed, 209 insertions, 17 deletions
diff --git a/src/game/AccountMgr.cpp b/src/game/AccountMgr.cpp
index 66660766dae..f2168cbc090 100644
--- a/src/game/AccountMgr.cpp
+++ b/src/game/AccountMgr.cpp
@@ -78,7 +78,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
uint64 guid = MAKE_NEW_GUID(guidlo, 0, HIGHGUID_PLAYER);
// kick if player currently
- if(Player* p = ObjectAccessor::FindPlayer(guid))
+ if(Player* p = ObjectAccessor::GetObjectInWorld(guid, (Player*)NULL))
{
WorldSession* s = p->GetSession();
s->KickPlayer(); // mark session to remove at next session list update
diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp
index f73f68e1f89..90bd4177ac1 100644
--- a/src/game/AchievementMgr.cpp
+++ b/src/game/AchievementMgr.cpp
@@ -35,6 +35,7 @@
#include "ProgressBar.h"
#include "SpellMgr.h"
+#include "MapManager.h"
INSTANTIATE_SINGLETON_1(AchievementGlobalMgr);
@@ -827,8 +828,8 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
if(!miscvalue1)
continue;
- Map const* map = GetPlayer()->GetMap();
- if(!map->IsDungeon())
+ Map const* map = GetPlayer()->IsInWorld() ? GetPlayer()->GetMap() : MapManager::Instance().FindMap(GetPlayer()->GetMapId(), GetPlayer()->GetInstanceId());
+ if(!map || !map->IsDungeon())
continue;
// search case
diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp
index 85a86f18cdf..d2d8044a322 100644
--- a/src/game/GameObject.cpp
+++ b/src/game/GameObject.cpp
@@ -76,7 +76,13 @@ void GameObject::CleanupsBeforeDelete()
// Possible crash at access to deleted GO in Unit::m_gameobj
if(uint64 owner_guid = GetOwnerGUID())
{
- if(Unit* owner = ObjectAccessor::GetUnit(*this,owner_guid))
+ Unit* owner = NULL;
+ if(IS_PLAYER_GUID(owner_guid))
+ owner = ObjectAccessor::GetObjectInWorld(owner_guid, (Player*)NULL);
+ else
+ owner = ObjectAccessor::GetUnit(*this,owner_guid);
+
+ if(owner)
owner->RemoveGameObject(this,false);
else
{
diff --git a/src/game/Group.cpp b/src/game/Group.cpp
index c08d1236c32..9db043b28f1 100644
--- a/src/game/Group.cpp
+++ b/src/game/Group.cpp
@@ -967,7 +967,7 @@ void Group::SendUpdate()
void Group::UpdatePlayerOutOfRange(Player* pPlayer)
{
- if(!pPlayer)
+ if(!pPlayer || !pPlayer->IsInWorld())
return;
Player *player;
diff --git a/src/game/LFGHandler.cpp b/src/game/LFGHandler.cpp
index 51735c01e02..09653ccb0bc 100644
--- a/src/game/LFGHandler.cpp
+++ b/src/game/LFGHandler.cpp
@@ -42,6 +42,10 @@ static void AttemptJoin(Player* _player)
if(!plr || plr==_player || plr->GetTeam() != _player->GetTeam())
continue;
+ //skip players not in world
+ if(!plr->IsInWorld())
+ continue;
+
// skip not auto add, not group leader cases
if(!plr->GetSession()->LookingForGroup_auto_add || plr->GetGroup() && plr->GetGroup()->GetLeaderGUID()!=plr->GetGUID())
continue;
@@ -98,6 +102,9 @@ static void AttemptAddMore(Player* _player)
if(!plr || plr==_player || plr->GetTeam() != _player->GetTeam())
continue;
+ if(!plr->IsInWorld())
+ continue;
+
// skip not auto join or in group
if(!plr->GetSession()->LookingForGroup_auto_join || plr->GetGroup() )
continue;
@@ -311,6 +318,9 @@ void WorldSession::SendLfgResult(uint32 type, uint32 entry, uint8 lfg_type)
if(!plr || plr->GetTeam() != _player->GetTeam())
continue;
+ if(!plr->IsInWorld())
+ continue;
+
if(!plr->m_lookingForGroup.HaveInSlot(entry, type))
continue;
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index 3ba7f81a8c2..cb9b3adf7bb 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -252,6 +252,10 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
continue;
}
+ //do not process players which are not in world
+ if(!(itr->second->IsInWorld()))
+ continue;
+
// check if target is globally visible for player
if (!(itr->second->IsVisibleGloballyFor(_player)))
continue;
diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp
index 7d7733763cd..d72931c89a3 100644
--- a/src/game/MovementHandler.cpp
+++ b/src/game/MovementHandler.cpp
@@ -156,6 +156,9 @@ void WorldSession::HandleMoveWorldportAckOpcode()
// resummon pet
GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
+
+ //lets process all delayed operations on successful teleport
+ GetPlayer()->ProcessDelayedOperations();
}
void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data)
@@ -202,6 +205,9 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data)
// resummon pet
GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
+
+ //lets process all delayed operations on successful teleport
+ GetPlayer()->ProcessDelayedOperations();
}
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp
index c60d368659a..bb9823ee71f 100644
--- a/src/game/NPCHandler.cpp
+++ b/src/game/NPCHandler.cpp
@@ -422,7 +422,7 @@ void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
uint64 npcGUID;
recv_data >> npcGUID;
- if(!GetPlayer()->isAlive())
+ if(!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive())
return;
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER);
@@ -442,7 +442,7 @@ void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
void WorldSession::SendBindPoint(Creature *npc)
{
// prevent set homebind to instances in any case
- if(sMapStore.LookupEntry(GetPlayer()->GetMapId())->Instanceable())
+ if(GetPlayer()->GetMap()->Instanceable())
return;
uint32 bindspell = 3286;
diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp
index b420e4af4b2..76fc02a7c02 100644
--- a/src/game/ObjectAccessor.cpp
+++ b/src/game/ObjectAccessor.cpp
@@ -60,7 +60,7 @@ ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const &u, uint64 guid)
if(IS_VEHICLE_GUID(guid))
return GetVehicle(guid);
- return u.GetMap()->GetCreature(guid);
+ return u.IsInWorld() ? u.GetMap()->GetCreature(guid) : NULL;
}
/*
@@ -135,7 +135,11 @@ Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const &p, uint64 guid, u
Player*
ObjectAccessor::FindPlayer(uint64 guid)
{
- return GetObjectInWorld(guid, (Player*)NULL);
+ Player * plr = GetObjectInWorld(guid, (Player*)NULL);
+ if(!plr || !plr->IsInWorld())
+ return NULL;
+
+ return plr;
}
Player*
@@ -145,7 +149,7 @@ ObjectAccessor::FindPlayerByName(const char *name)
HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
HashMapHolder<Player>::MapType::iterator iter = m.begin();
for(; iter != m.end(); ++iter)
- if( ::strcmp(name, iter->second->GetName()) == 0 )
+ if(iter->second->IsInWorld() && ( ::strcmp(name, iter->second->GetName()) == 0 ))
return iter->second;
return NULL;
}
diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h
index 80aac0bcf92..fea928a54eb 100644
--- a/src/game/ObjectAccessor.h
+++ b/src/game/ObjectAccessor.h
@@ -103,8 +103,14 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor,
if(!guid)
return NULL;
- if(IS_PLAYER_GUID(guid))
- return (Unit*)HashMapHolder<Player>::Find(guid);
+ if (IS_PLAYER_GUID(guid))
+ {
+ Unit * u = (Unit*)HashMapHolder<Player>::Find(guid);
+ if(!u || !u->IsInWorld())
+ return NULL;
+
+ return u;
+ }
if(IS_CREATURE_GUID(guid))
return (Unit*)HashMapHolder<Creature>::Find(guid);
diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp
index ad3389c8ab4..3d92caa406c 100644
--- a/src/game/PetHandler.cpp
+++ b/src/game/PetHandler.cpp
@@ -500,6 +500,9 @@ void WorldSession::HandlePetAbandon( WorldPacket & recv_data )
recv_data >> guid; //pet guid
sLog.outDetail( "HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid) );
+ if(!_player->IsInWorld())
+ return;
+
// pet/charmed
Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
if(pet)
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 946a47cf098..15dc3c69bd8 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -341,6 +341,11 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
mSemaphoreTeleport_Near = false;
mSemaphoreTeleport_Far = false;
+ m_DelayedOperations = 0;
+ m_bCanDelayTeleport = false;
+ m_bHasDelayedTeleport = false;
+ m_teleport_options = 0;
+
pTrader = 0;
ClearTrade();
@@ -1122,7 +1127,10 @@ void Player::Update( uint32 p_time )
// Having this would prevent more aura charges to be dropped, so let's crash
assert (!m_spellModTakingSpell);
+ //used to implement delayed far teleports
+ SetCanDelayTeleport(true);
Unit::Update( p_time );
+ SetCanDelayTeleport(false);
time_t now = time (NULL);
@@ -1378,8 +1386,12 @@ void Player::Update( uint32 p_time )
//if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID())))
{
RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);
- return;
}
+
+ //we should execute delayed teleports only for alive(!) players
+ //because we don't want player's ghost teleported from graveyard
+ if(IsHasDelayedTeleport() && isAlive())
+ TeleportTo(m_teleport_dest, m_teleport_options);
}
void Player::setDeathState(DeathState s)
@@ -1685,6 +1697,21 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if ((GetMapId() == mapid) && (!m_transport))
{
+ //lets reset far teleport flag if it wasn't reset during chained teleports
+ SetSemaphoreTeleportFar(false);
+ //setup delayed teleport flag
+ SetDelayedTeleportFlag(IsCanDelayTeleport());
+ //if teleport spell is casted in Unit::Update() func
+ //then we need to delay it until update process will be finished
+ if(IsHasDelayedTeleport())
+ {
+ SetSemaphoreTeleportNear(true);
+ //lets save teleport destination for player
+ m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
+ m_teleport_options = options;
+ return true;
+ }
+
if (!(options & TELE_TO_NOT_UNSUMMON_PET))
{
//same map, only remove pet if out of range for new position
@@ -1728,6 +1755,21 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
Map *map = MapManager::Instance().FindMap(mapid);
if (!map || map->CanEnter(this))
{
+ //lets reset near teleport flag if it wasn't reset during chained teleports
+ SetSemaphoreTeleportNear(false);
+ //setup delayed teleport flag
+ SetDelayedTeleportFlag(IsCanDelayTeleport());
+ //if teleport spell is casted in Unit::Update() func
+ //then we need to delay it until update process will be finished
+ if(IsHasDelayedTeleport())
+ {
+ SetSemaphoreTeleportFar(true);
+ //lets save teleport destination for player
+ m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
+ m_teleport_options = options;
+ return true;
+ }
+
SetSelection(0);
CombatStop();
@@ -1757,6 +1799,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if(IsNonMeleeSpellCasted(true))
InterruptNonMeleeSpells(true);
+ //remove auras before removing from map...
+ RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING);
+
if(!GetSession()->PlayerLogout())
{
// send transfer packets
@@ -1803,8 +1848,6 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// if the player is saved before worldportack (at logout for example)
// this will be used instead of the current location in SaveToDB
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING);
-
// move packet sent by client always after far teleport
// code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet
SetSemaphoreTeleportFar(true);
@@ -1815,6 +1858,53 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
return true;
}
+void Player::ProcessDelayedOperations()
+{
+ if(m_DelayedOperations == 0)
+ return;
+
+ if(m_DelayedOperations & DELAYED_RESURRECT_PLAYER)
+ {
+ ResurrectPlayer(0.0f, false);
+
+ if(GetMaxHealth() > m_resurrectHealth)
+ SetHealth( m_resurrectHealth );
+ else
+ SetHealth( GetMaxHealth() );
+
+ if(GetMaxPower(POWER_MANA) > m_resurrectMana)
+ SetPower(POWER_MANA, m_resurrectMana );
+ else
+ SetPower(POWER_MANA, GetMaxPower(POWER_MANA) );
+
+ SetPower(POWER_RAGE, 0 );
+ SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY) );
+
+ SpawnCorpseBones();
+ }
+
+ if(m_DelayedOperations & DELAYED_SAVE_PLAYER)
+ {
+ SaveToDB();
+ }
+
+ if(m_DelayedOperations & DELAYED_SPELL_CAST_DESERTER)
+ {
+ CastSpell(this, 26013, true); // Deserter
+ }
+
+ //we have executed ALL delayed ops, so clear the flag
+ m_DelayedOperations = 0;
+}
+
+void Player::ScheduleDelayedOperation(uint32 operation)
+{
+ if(operation >= DELAYED_END)
+ return;
+
+ m_DelayedOperations |= operation;
+}
+
void Player::AddToWorld()
{
///- Do not add/remove the player from the object storage
@@ -12489,7 +12579,11 @@ Quest const * Player::GetNextQuest( uint64 guid, Quest const *pQuest )
}
else
{
- GameObject *pGameObject = GetMap()->GetGameObject(guid);
+ //we should obtain map pointer from GetMap() in 99% of cases. Special case
+ //only for quests which cast teleport spells on player
+ Map * _map = IsInWorld() ? GetMap() : MapManager::Instance().FindMap(GetMapId(), GetInstanceId());
+ ASSERT(_map);
+ GameObject *pGameObject = _map->GetGameObject(guid);
if( pGameObject )
{
pObject = (Object*)pGameObject;
@@ -12823,6 +12917,10 @@ void Player::IncompleteQuest( uint32 quest_id )
void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce )
{
+ //this THING should be here to protect code from quest, which cast on player far teleport as a reward
+ //should work fine, cause far teleport will be executed in Player::Update()
+ SetCanDelayTeleport(true);
+
uint32 quest_id = pQuest->GetQuestId();
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++ )
@@ -13015,6 +13113,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
if( !HasAura(itr->second->spellId) )
CastSpell(this,itr->second->spellId,true);
}
+
+ //lets remove flag for delayed teleports
+ SetCanDelayTeleport(false);
}
void Player::FailQuest( uint32 quest_id )
@@ -15941,6 +16042,13 @@ void Player::SaveToDB()
// delay auto save at any saves (manual, in code, or autosave)
m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
+ //lets allow only players in world to be saved
+ if(IsBeingTeleportedFar())
+ {
+ ScheduleDelayedOperation(DELAYED_SAVE_PLAYER);
+ return;
+ }
+
// first save/honor gain after midnight will also update the player's honor fields
UpdateHonorFields();
@@ -18398,7 +18506,16 @@ void Player::LeaveBattleground(bool teleportToEntryPoint)
if( bg->isBattleGround() && !isGameMaster() && sWorld.getConfig(CONFIG_BATTLEGROUND_CAST_DESERTER) )
{
if( bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN )
+ {
+ //lets check if player was teleported from BG and schedule delayed Deserter spell cast
+ if(IsBeingTeleportedFar())
+ {
+ ScheduleDelayedOperation(DELAYED_SPELL_CAST_DESERTER);
+ return;
+ }
+
CastSpell(this, 26013, true); // Deserter
+ }
}
}
}
@@ -19755,6 +19872,14 @@ void Player::ResurectUsingRequestData()
if(IS_PLAYER_GUID(m_resurrectGUID))
TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation());
+ //we cannot resurrect player when we triggered far teleport
+ //player will be resurrected upon teleportation
+ if(IsBeingTeleportedFar())
+ {
+ ScheduleDelayedOperation(DELAYED_RESURRECT_PLAYER);
+ return;
+ }
+
ResurrectPlayer(0.0f,false);
if(GetMaxHealth() > m_resurrectHealth)
diff --git a/src/game/Player.h b/src/game/Player.h
index 8ffcd55e4ba..38de51033c3 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -780,6 +780,14 @@ enum PlayerLoginQueryIndex
MAX_PLAYER_LOGIN_QUERY = 21
};
+enum PlayerDelayedOperations
+{
+ DELAYED_SAVE_PLAYER = 1,
+ DELAYED_RESURRECT_PLAYER = 2,
+ DELAYED_SPELL_CAST_DESERTER = 4,
+ DELAYED_END
+};
+
// Player summoning auto-decline time (in secs)
#define MAX_PLAYER_SUMMON_DELAY (2*MINUTE)
#define MAX_MONEY_AMOUNT (0x7FFFFFFF-1)
@@ -1716,6 +1724,7 @@ class TRINITY_DLL_SPEC Player : public Unit
bool IsBeingTeleportedFar() const { return mSemaphoreTeleport_Far; }
void SetSemaphoreTeleportNear(bool semphsetting) { mSemaphoreTeleport_Near = semphsetting; }
void SetSemaphoreTeleportFar(bool semphsetting) { mSemaphoreTeleport_Far = semphsetting; }
+ void ProcessDelayedOperations();
void CheckExploreSystem(void);
@@ -2347,6 +2356,13 @@ class TRINITY_DLL_SPEC Player : public Unit
int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest);
void AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData );
+ bool IsCanDelayTeleport() const { return m_bCanDelayTeleport; }
+ void SetCanDelayTeleport(bool setting) { m_bCanDelayTeleport = setting; }
+ bool IsHasDelayedTeleport() const { return m_bHasDelayedTeleport; }
+ void SetDelayedTeleportFlag(bool setting) { m_bHasDelayedTeleport = setting; }
+
+ void ScheduleDelayedOperation(uint32 operation);
+
GridReference<Player> m_gridRef;
MapReference m_mapRef;
@@ -2363,9 +2379,14 @@ class TRINITY_DLL_SPEC Player : public Unit
// Current teleport data
WorldLocation m_teleport_dest;
+ uint32 m_teleport_options;
bool mSemaphoreTeleport_Near;
bool mSemaphoreTeleport_Far;
+ uint32 m_DelayedOperations;
+ bool m_bCanDelayTeleport;
+ bool m_bHasDelayedTeleport;
+
// Temporary removed pet cache
uint32 m_temporaryUnsummonedPetNumber;
uint32 m_oldpetspell;
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index dfe7bfb0df9..df5334e3324 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -8338,7 +8338,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
return false;
// dead units can neither attack nor be attacked
- if(!isAlive() || !victim->isAlive())
+ if(!isAlive() || !victim->IsInWorld() || !victim->isAlive())
return false;
// player cannot attack in mount state
diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp
index 44bab655886..0724aac320e 100644
--- a/src/game/WorldSession.cpp
+++ b/src/game/WorldSession.cpp
@@ -310,7 +310,13 @@ void WorldSession::LogoutPlayer(bool Save)
///- Teleport to home if the player is in an invalid instance
if(!_player->m_InstanceValid && !_player->isGameMaster())
+ {
_player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation());
+ //this is a bad place to call for far teleport because we need player to be in world for successful logout
+ //maybe we should implement delayed far teleport logout?
+ while(_player->IsBeingTeleportedFar())
+ HandleMoveWorldportAckOpcode();
+ }
sOutdoorPvPMgr.HandlePlayerLeaveZone(_player,_player->GetZoneId());