diff options
author | Treeston <treeston.mmoc@gmail.com> | 2018-09-17 13:14:56 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-11-08 23:57:28 +0100 |
commit | e8e8e4b9d6ae72615334c5ef5f62d14a77729f55 (patch) | |
tree | 3ecb0ea85020d2cadb7ef9663571f41d94f4323a | |
parent | 7c062db94b1c2d28329c5f0ddc2fee74a6c07c35 (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.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 6 | ||||
-rw-r--r-- | src/server/game/Handlers/MovementHandler.cpp | 114 |
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*/) |