aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2018-09-17 13:14:56 +0200
committerShauren <shauren.trinity@gmail.com>2021-11-08 23:57:28 +0100
commite8e8e4b9d6ae72615334c5ef5f62d14a77729f55 (patch)
tree3ecb0ea85020d2cadb7ef9663571f41d94f4323a
parent7c062db94b1c2d28329c5f0ddc2fee74a6c07c35 (diff)
Core/Player: Delay resurrection on release for unreachable maps until teleport has completed. Closes #21481.
(cherry picked from commit 28591fd1658e3e4842d64f330f27c233dc69aad2)
-rw-r--r--src/server/game/Entities/Player/Player.cpp8
-rw-r--r--src/server/game/Entities/Player/Player.h6
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp114
3 files changed, 69 insertions, 59 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 90795081b39..3154dbcc6e9 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1411,6 +1411,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
UnsummonPetTemporaryIfAny();
}
+ if (!IsAlive() && options & TELE_REVIVE_AT_TELEPORT)
+ ResurrectPlayer(0.5f);
+
if (!(options & TELE_TO_NOT_LEAVE_COMBAT))
CombatStop();
@@ -4740,10 +4743,11 @@ void Player::RepopAtGraveyard()
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId());
+ bool shouldResurrect = false;
// Such zones are considered unreachable as a ghost and the player must be automatically revived
if ((!IsAlive() && zone && zone->Flags[0] & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPhaseShift(), GetPositionX(), GetPositionY()))
{
- ResurrectPlayer(0.5f);
+ shouldResurrect = true;
SpawnCorpseBones();
}
@@ -4767,7 +4771,7 @@ void Player::RepopAtGraveyard()
// and don't show spirit healer location
if (ClosestGrave)
{
- TeleportTo(ClosestGrave->Loc);
+ TeleportTo(ClosestGrave->Loc, shouldResurrect ? TELE_REVIVE_AT_TELEPORT : 0);
if (isDead()) // not send if alive, because it used in TeleportTo()
{
WorldPackets::Misc::DeathReleaseLoc packet;
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 0fed004033e..df930b20727 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -806,7 +806,8 @@ enum TeleportToOptions
TELE_TO_NOT_UNSUMMON_PET = 0x08,
TELE_TO_SPELL = 0x10,
TELE_TO_TRANSPORT_TELEPORT = 0x20, // 3.3.5 only
- TELE_TO_SEAMLESS = 0x40
+ TELE_REVIVE_AT_TELEPORT = 0x40,
+ TELE_TO_SEAMLESS = 0x80
};
/// Type of environmental damages
@@ -2125,7 +2126,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SetSkillPermBonus(uint32 pos, uint16 bonus) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::Skill).ModifyValue(&UF::SkillInfo::SkillPermBonus, pos), bonus); }
WorldLocation& GetTeleportDest() { return m_teleport_dest; }
- bool IsBeingTeleported() const { return mSemaphoreTeleport_Near || mSemaphoreTeleport_Far; }
+ uint32 GetTeleportOptions() const { return m_teleport_options; }
+ bool IsBeingTeleported() const { return IsBeingTeleportedNear() || IsBeingTeleportedFar(); }
bool IsBeingTeleportedNear() const { return mSemaphoreTeleport_Near; }
bool IsBeingTeleportedFar() const { return mSemaphoreTeleport_Far; }
bool IsBeingTeleportedSeamlessly() const { return IsBeingTeleportedFar() && m_teleport_options & TELE_TO_SEAMLESS; }
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index d3ee1a6672f..fafbb4d751e 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -47,15 +47,16 @@ void WorldSession::HandleMoveWorldportAckOpcode(WorldPackets::Movement::WorldPor
void WorldSession::HandleMoveWorldportAck()
{
+ Player* player = GetPlayer();
// ignore unexpected far teleports
- if (!GetPlayer()->IsBeingTeleportedFar())
+ if (!player->IsBeingTeleportedFar())
return;
- bool seamlessTeleport = GetPlayer()->IsBeingTeleportedSeamlessly();
- GetPlayer()->SetSemaphoreTeleportFar(false);
+ bool seamlessTeleport = player->IsBeingTeleportedSeamlessly();
+ 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))
@@ -69,107 +70,110 @@ 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 %s (%s), porting player to homebind", loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown", GetPlayer()->GetGUID().ToString().c_str(), GetPlayer()->GetName().c_str());
- GetPlayer()->TeleportTo(GetPlayer()->m_homebind);
+ TC_LOG_ERROR("network", "Map %d (%s) could not be created for player %s (%s), porting player to homebind", loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown", player->GetGUID().ToString().c_str(), player->GetName().c_str());
+ player->TeleportTo(player->m_homebind);
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);
WorldPackets::Movement::ResumeToken resumeToken;
- resumeToken.SequenceIndex = _player->m_movementCounter;
+ resumeToken.SequenceIndex = player->m_movementCounter;
resumeToken.Reason = seamlessTeleport ? 2 : 1;
SendPacket(resumeToken.Write());
if (!seamlessTeleport)
- GetPlayer()->SendInitialPacketsBeforeAddToMap();
+ player->SendInitialPacketsBeforeAddToMap();
- if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer(), !seamlessTeleport))
+ if (!player->GetMap()->AddPlayerToMap(player, !seamlessTeleport))
{
TC_LOG_ERROR("network", "WORLD: failed to teleport player %s (%s) to map %d (%s) because of unknown reason!",
- GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str(), loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown");
- GetPlayer()->ResetMap();
- GetPlayer()->SetMap(oldMap);
- GetPlayer()->TeleportTo(GetPlayer()->m_homebind);
+ player->GetName().c_str(), player->GetGUID().ToString().c_str(), loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown");
+ player->ResetMap();
+ player->SetMap(oldMap);
+ player->TeleportTo(player->m_homebind);
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);
}
}
if (!seamlessTeleport)
- GetPlayer()->SendInitialPacketsAfterAddToMap();
+ player->SendInitialPacketsAfterAddToMap();
else
{
- GetPlayer()->UpdateVisibilityForPlayer();
- if (Garrison* garrison = GetPlayer()->GetGarrison())
+ player->UpdateVisibilityForPlayer();
+ if (Garrison* garrison = player->GetGarrison())
garrison->SendRemoteInfo();
}
// flight fast teleport case
- if (GetPlayer()->IsInFlight())
+ if (player->IsInFlight())
{
- if (!_player->InBattleground())
+ if (!player->InBattleground())
{
if (!seamlessTeleport)
{
// 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->ID)
+ if (player->GetCorpseLocation().GetMapId() == mEntry->ID)
{
- GetPlayer()->ResurrectPlayer(0.5f, false);
- GetPlayer()->SpawnCorpseBones();
+ player->ResurrectPlayer(0.5f);
+ player->SpawnCorpseBones();
}
}
@@ -184,34 +188,34 @@ void WorldSession::HandleMoveWorldportAck()
if (time_t timeReset = sInstanceSaveMgr->GetResetTimeFor(mEntry->ID, diff))
{
uint32 timeleft = uint32(timeReset - GameTime::GetGameTime());
- GetPlayer()->SendInstanceResetWarning(mEntry->ID, diff, timeleft, true);
+ player->SendInstanceResetWarning(mEntry->ID, diff, timeleft, true);
}
}
}
// check if instance is valid
- if (!GetPlayer()->CheckInstanceValidity(false))
- GetPlayer()->m_InstanceValid = false;
+ if (!player->CheckInstanceValidity(false))
+ player->m_InstanceValid = false;
}
// 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()->HasPlayerFlag(PLAYER_FLAGS_IN_PVP))
- GetPlayer()->UpdatePvP(false, false);
+ else if (player->IsPvP() && !player->HasPlayerFlag(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::HandleSuspendTokenResponse(WorldPackets::Movement::SuspendTokenResponse& /*suspendTokenResponse*/)