Core/Player: Delay resurrection on release for unreachable maps until teleport has completed. Closes #21481.

This commit is contained in:
Treeston
2018-09-17 13:14:56 +02:00
parent 003cc56d70
commit 28591fd165
3 changed files with 68 additions and 57 deletions

View File

@@ -43,14 +43,15 @@ void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recvData*/)
void WorldSession::HandleMoveWorldportAck()
{
Player* player = GetPlayer();
// ignore unexpected far teleports
if (!GetPlayer()->IsBeingTeleportedFar())
if (!player->IsBeingTeleportedFar())
return;
GetPlayer()->SetSemaphoreTeleportFar(false);
player->SetSemaphoreTeleportFar(false);
// get the teleport destination
WorldLocation const& loc = GetPlayer()->GetTeleportDest();
WorldLocation const& loc = player->GetTeleportDest();
// possible errors in the coordinate validity check
if (!MapManager::IsValidMapCoord(loc))
@@ -64,90 +65,93 @@ void WorldSession::HandleMoveWorldportAck()
InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(loc.GetMapId());
// reset instance validity, except if going to an instance inside an instance
if (GetPlayer()->m_InstanceValid == false && !mInstance)
GetPlayer()->m_InstanceValid = true;
if (player->m_InstanceValid == false && !mInstance)
player->m_InstanceValid = true;
Map* oldMap = GetPlayer()->GetMap();
Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer());
Map* oldMap = player->GetMap();
Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), player);
if (GetPlayer()->IsInWorld())
if (player->IsInWorld())
{
TC_LOG_ERROR("network", "%s %s is still in world when teleported from map %s (%u) to new map %s (%u)", GetPlayer()->GetGUID().ToString().c_str(), GetPlayer()->GetName().c_str(), oldMap->GetMapName(), oldMap->GetId(), newMap ? newMap->GetMapName() : "Unknown", loc.GetMapId());
oldMap->RemovePlayerFromMap(GetPlayer(), false);
TC_LOG_ERROR("network", "%s %s is still in world when teleported from map %s (%u) to new map %s (%u)", player->GetGUID().ToString().c_str(), player->GetName().c_str(), oldMap->GetMapName(), oldMap->GetId(), newMap ? newMap->GetMapName() : "Unknown", loc.GetMapId());
oldMap->RemovePlayerFromMap(player, false);
}
// relocate the player to the teleport destination
// the CannotEnter checks are done in TeleporTo but conditions may change
// while the player is in transit, for example the map may get full
if (!newMap || newMap->CannotEnter(GetPlayer()))
if (!newMap || newMap->CannotEnter(player))
{
TC_LOG_ERROR("network", "Map %d (%s) could not be created for player %d (%s), porting player to homebind", loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown", GetPlayer()->GetGUID().GetCounter(), GetPlayer()->GetName().c_str());
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
TC_LOG_ERROR("network", "Map %d (%s) could not be created for player %d (%s), porting player to homebind", loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown", player->GetGUID().GetCounter(), player->GetName().c_str());
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->GetOrientation());
return;
}
float z = loc.GetPositionZ() + GetPlayer()->GetHoverOffset();
GetPlayer()->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation());
GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ());
float z = loc.GetPositionZ() + player->GetHoverOffset();
player->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation());
player->SetFallInformation(0, player->GetPositionZ());
GetPlayer()->ResetMap();
GetPlayer()->SetMap(newMap);
player->ResetMap();
player->SetMap(newMap);
GetPlayer()->SendInitialPacketsBeforeAddToMap();
if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer()))
player->SendInitialPacketsBeforeAddToMap();
if (!player->GetMap()->AddPlayerToMap(player))
{
TC_LOG_ERROR("network", "WORLD: failed to teleport player %s (%d) to map %d (%s) because of unknown reason!",
GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().GetCounter(), loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown");
GetPlayer()->ResetMap();
GetPlayer()->SetMap(oldMap);
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
player->GetName().c_str(), player->GetGUID().GetCounter(), loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown");
player->ResetMap();
player->SetMap(oldMap);
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->GetOrientation());
return;
}
// battleground state prepare (in case join to BG), at relogin/tele player not invited
// only add to bg group and object, if the player was invited (else he entered through command)
if (_player->InBattleground())
if (player->InBattleground())
{
// cleanup setting if outdated
if (!mEntry->IsBattlegroundOrArena())
{
// We're not in BG
_player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE);
player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE);
// reset destination bg team
_player->SetBGTeam(0);
player->SetBGTeam(0);
}
// join to bg case
else if (Battleground* bg = _player->GetBattleground())
else if (Battleground* bg = player->GetBattleground())
{
if (_player->IsInvitedForBattlegroundInstance(_player->GetBattlegroundId()))
bg->AddPlayer(_player);
if (player->IsInvitedForBattlegroundInstance(player->GetBattlegroundId()))
bg->AddPlayer(player);
}
}
GetPlayer()->SendInitialPacketsAfterAddToMap();
player->SendInitialPacketsAfterAddToMap();
// flight fast teleport case
if (GetPlayer()->IsInFlight())
if (player->IsInFlight())
{
if (!_player->InBattleground())
if (!player->InBattleground())
{
// short preparations to continue flight
MovementGenerator* movementGenerator = GetPlayer()->GetMotionMaster()->GetCurrentMovementGenerator();
movementGenerator->Initialize(GetPlayer());
MovementGenerator* movementGenerator = player->GetMotionMaster()->GetCurrentMovementGenerator();
movementGenerator->Initialize(player);
return;
}
// battleground state prepare, stop flight
GetPlayer()->FinishTaxiFlight();
player->FinishTaxiFlight();
}
if (!player->IsAlive() && player->GetTeleportOptions() & TELE_REVIVE_AT_TELEPORT)
player->ResurrectPlayer(0.5f);
// resurrect character at enter into instance where his corpse exist after add to map
if (mEntry->IsDungeon() && !GetPlayer()->IsAlive())
if (mEntry->IsDungeon() && !player->IsAlive())
{
if (GetPlayer()->GetCorpseLocation().GetMapId() == mEntry->MapID)
if (player->GetCorpseLocation().GetMapId() == mEntry->MapID)
{
GetPlayer()->ResurrectPlayer(0.5f, false);
GetPlayer()->SpawnCorpseBones();
player->ResurrectPlayer(0.5f);
player->SpawnCorpseBones();
}
}
@@ -155,7 +159,7 @@ void WorldSession::HandleMoveWorldportAck()
if (mInstance)
{
// check if this instance has a reset time and send it to player if so
Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid());
Difficulty diff = player->GetDifficulty(mEntry->IsRaid());
if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff))
{
if (mapDiff->resetTime)
@@ -163,14 +167,14 @@ void WorldSession::HandleMoveWorldportAck()
if (time_t timeReset = sInstanceSaveMgr->GetResetTimeFor(mEntry->MapID, diff))
{
uint32 timeleft = uint32(timeReset - GameTime::GetGameTime());
GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft, true);
player->SendInstanceResetWarning(mEntry->MapID, diff, timeleft, true);
}
}
}
// check if instance is valid
if (!GetPlayer()->CheckInstanceValidity(false))
GetPlayer()->m_InstanceValid = false;
if (!player->CheckInstanceValidity(false))
player->m_InstanceValid = false;
// instance mounting is handled in InstanceTemplate
allowMount = mInstance->AllowMount;
@@ -178,26 +182,26 @@ void WorldSession::HandleMoveWorldportAck()
// mount allow check
if (!allowMount)
_player->RemoveAurasByType(SPELL_AURA_MOUNTED);
player->RemoveAurasByType(SPELL_AURA_MOUNTED);
// update zone immediately, otherwise leave channel will cause crash in mtmap
uint32 newzone, newarea;
GetPlayer()->GetZoneAndAreaId(newzone, newarea);
GetPlayer()->UpdateZone(newzone, newarea);
player->GetZoneAndAreaId(newzone, newarea);
player->UpdateZone(newzone, newarea);
// honorless target
if (GetPlayer()->pvpInfo.IsHostile)
GetPlayer()->CastSpell(GetPlayer(), 2479, true);
if (player->pvpInfo.IsHostile)
player->CastSpell(player, 2479, true);
// in friendly area
else if (GetPlayer()->IsPvP() && !GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
GetPlayer()->UpdatePvP(false, false);
else if (player->IsPvP() && !player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
player->UpdatePvP(false, false);
// resummon pet
GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
player->ResummonPetTemporaryUnSummonedIfAny();
//lets process all delayed operations on successful teleport
GetPlayer()->ProcessDelayedOperations();
player->ProcessDelayedOperations();
}
void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData)