fix(Core/Maps): Enabled dead players to be resurrected at the dungeon entrance if cannot enter it due to some reasons (#7236)

- Closes #6790
This commit is contained in:
UltraNix
2021-08-07 16:10:07 +02:00
committed by GitHub
parent 418a3814fd
commit 5b057798e7
11 changed files with 89 additions and 43 deletions

View File

@@ -1435,10 +1435,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// Check enter rights before map getting to avoid creating instance copy for player
// this check not dependent from map instance copy and same for all instance copies of selected map
if (!(options & TELE_TO_GM_MODE) && !sMapMgr->CanPlayerEnter(mapid, this, false))
if (!(options & TELE_TO_GM_MODE) && sMapMgr->PlayerCannotEnter(mapid, this, false))
return false;
// if CanPlayerEnter -> CanEnter: checked above
// if PlayerCannotEnter -> CanEnter: checked above
{
//lets reset near teleport flag if it wasn't reset during chained teleports
SetSemaphoreTeleportNear(0);

View File

@@ -6971,12 +6971,12 @@ bool Player::CheckInstanceLoginValid()
return false;
}
// pussywizard: check CanEnter for GetMap(), because in CanPlayerEnter it is called for a map decided before loading screen (can change)
if (!GetMap()->CanEnter(this, true))
// pussywizard: check CanEnter for GetMap(), because in PlayerCannotEnter it is called for a map decided before loading screen (can change)
if (GetMap()->CannotEnter(this, true))
return false;
// do checks for satisfy accessreqs, instance full, encounter in progress (raid), perm bind group != perm bind player
return sMapMgr->CanPlayerEnter(GetMap()->GetId(), this, true);
return sMapMgr->PlayerCannotEnter(GetMap()->GetId(), this, true) == Map::CAN_ENTER;
}
bool Player::CheckInstanceCount(uint32 instanceId) const

View File

@@ -771,8 +771,36 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
bool teleported = false;
if (player->GetMapId() != at->target_mapId)
{
if (!sMapMgr->CanPlayerEnter(at->target_mapId, player, false))
if (Map::EnterState denyReason = sMapMgr->PlayerCannotEnter(at->target_mapId, player, false))
{
bool reviveAtTrigger = false; // should we revive the player if he is trying to enter the correct instance?
switch (denyReason)
{
case Map::CANNOT_ENTER_NOT_IN_RAID:
case Map::CANNOT_ENTER_INSTANCE_BIND_MISMATCH:
case Map::CANNOT_ENTER_TOO_MANY_INSTANCES:
case Map::CANNOT_ENTER_MAX_PLAYERS:
case Map::CANNOT_ENTER_ZONE_IN_COMBAT:
reviveAtTrigger = true;
break;
default:
break;
}
if (reviveAtTrigger) // check if the player is touching the areatrigger leading to the map his corpse is on
{
if (!player->IsAlive() && player->HasCorpse())
{
if (player->GetCorpseLocation().GetMapId() == at->target_mapId)
{
player->ResurrectPlayer(0.5f);
player->SpawnCorpseBones();
}
}
}
return;
}
if (Group* group = player->GetGroup())
if (group->isLFGGroup() && player->GetMap()->IsDungeon())

View File

@@ -77,7 +77,7 @@ void WorldSession::HandleMoveWorldportAck()
Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer());
// the CanEnter 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->CanEnter(GetPlayer(), false))
if (!newMap || newMap->CannotEnter(GetPlayer(), false))
{
LOG_ERROR("network.opcode", "Map %d could not be created for player %s, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUID().ToString().c_str());
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());

View File

@@ -2657,19 +2657,19 @@ void InstanceMap::InitVisibilityDistance()
/*
Do map specific checks to see if the player can enter
*/
bool InstanceMap::CanEnter(Player* player, bool loginCheck)
Map::EnterState InstanceMap::CannotEnter(Player* player, bool loginCheck)
{
if (!loginCheck && player->GetMapRef().getTarget() == this)
{
LOG_ERROR("maps", "InstanceMap::CanEnter - player %s (%s) already in map %d, %d, %d!",
player->GetName().c_str(), player->GetGUID().ToString().c_str(), GetId(), GetInstanceId(), GetSpawnMode());
ABORT();
return false;
return CANNOT_ENTER_ALREADY_IN_MAP;
}
// allow GM's to enter
if (player->IsGameMaster())
return Map::CanEnter(player, loginCheck);
return Map::CannotEnter(player, loginCheck);
// cannot enter if the instance is full (player cap), GMs don't count
uint32 maxPlayers = GetMaxPlayers();
@@ -2677,7 +2677,7 @@ bool InstanceMap::CanEnter(Player* player, bool loginCheck)
{
LOG_DEBUG("maps", "MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName().c_str());
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
return false;
return CANNOT_ENTER_MAX_PLAYERS;
}
// cannot enter while an encounter is in progress on raids
@@ -2685,7 +2685,7 @@ bool InstanceMap::CanEnter(Player* player, bool loginCheck)
if (checkProgress && GetInstanceScript() && GetInstanceScript()->IsEncounterInProgress())
{
player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
return false;
return CANNOT_ENTER_ZONE_IN_COMBAT;
}
// xinef: dont allow LFG Group to enter other instance that is selected
@@ -2694,7 +2694,7 @@ bool InstanceMap::CanEnter(Player* player, bool loginCheck)
if (!sLFGMgr->inLfgDungeonMap(group->GetGUID(), GetId(), GetDifficulty()))
{
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAP_NOT_ALLOWED);
return false;
return CANNOT_ENTER_UNSPECIFIED_REASON;
}
// cannot enter if instance is in use by another party/soloer that have a permanent save in the same instance id
@@ -2710,18 +2710,18 @@ bool InstanceMap::CanEnter(Player* player, bool loginCheck)
if (!player->GetGroup()) // player has not group and there is someone inside, deny entry
{
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
return false;
return CANNOT_ENTER_INSTANCE_BIND_MISMATCH;
}
// player inside instance has no group or his groups is different to entering player's one, deny entry
if (!iPlayer->GetGroup() || iPlayer->GetGroup() != player->GetGroup())
{
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
return false;
return CANNOT_ENTER_INSTANCE_BIND_MISMATCH;
}
break;
}
return Map::CanEnter(player, loginCheck);
return Map::CannotEnter(player, loginCheck);
}
/*
@@ -3020,21 +3020,21 @@ void BattlegroundMap::InitVisibilityDistance()
m_VisibleDistance = 30.0f;
}
bool BattlegroundMap::CanEnter(Player* player, bool loginCheck)
Map::EnterState BattlegroundMap::CannotEnter(Player* player, bool loginCheck)
{
if (!loginCheck && player->GetMapRef().getTarget() == this)
{
LOG_ERROR("maps", "BGMap::CanEnter - player %s is already in map!", player->GetGUID().ToString().c_str());
ABORT();
return false;
return CANNOT_ENTER_ALREADY_IN_MAP;
}
if (player->GetBattlegroundId() != GetInstanceId())
return false;
return CANNOT_ENTER_INSTANCE_BIND_MISMATCH;
// pussywizard: no need to check player limit here, invitations are limited by Battleground::GetFreeSlotsForTeam
return Map::CanEnter(player, loginCheck);
return Map::CannotEnter(player, loginCheck);
}
bool BattlegroundMap::AddPlayerToMap(Player* player)

View File

@@ -377,7 +377,25 @@ public:
[[nodiscard]] uint32 GetInstanceId() const { return i_InstanceId; }
[[nodiscard]] uint8 GetSpawnMode() const { return (i_spawnMode); }
virtual bool CanEnter(Player* /*player*/, bool /*loginCheck = false*/) { return true; }
enum EnterState
{
CAN_ENTER = 0,
CANNOT_ENTER_ALREADY_IN_MAP = 1, // Player is already in the map
CANNOT_ENTER_NO_ENTRY, // No map entry was found for the target map ID
CANNOT_ENTER_UNINSTANCED_DUNGEON, // No instance template was found for dungeon map
CANNOT_ENTER_DIFFICULTY_UNAVAILABLE, // Requested instance difficulty is not available for target map
CANNOT_ENTER_NOT_IN_RAID, // Target instance is a raid instance and the player is not in a raid group
CANNOT_ENTER_CORPSE_IN_DIFFERENT_INSTANCE, // Player is dead and their corpse is not in target instance
CANNOT_ENTER_INSTANCE_BIND_MISMATCH, // Player's permanent instance save is not compatible with their group's current instance bind
CANNOT_ENTER_TOO_MANY_INSTANCES, // Player has entered too many instances recently
CANNOT_ENTER_MAX_PLAYERS, // Target map already has the maximum number of players allowed
CANNOT_ENTER_ZONE_IN_COMBAT, // A boss encounter is currently in progress on the target map
CANNOT_ENTER_UNSPECIFIED_REASON
};
virtual EnterState CannotEnter(Player* /*player*/, bool /*loginCheck = false*/) { return CAN_ENTER; }
[[nodiscard]] const char* GetMapName() const;
// have meaning only for instanced map (that have set real difficulty)
@@ -756,7 +774,7 @@ public:
[[nodiscard]] InstanceScript const* GetInstanceScript() const { return instance_data; }
void PermBindAllPlayers();
void UnloadAll() override;
bool CanEnter(Player* player, bool loginCheck = false) override;
EnterState CannotEnter(Player* player, bool loginCheck = false) override;
void SendResetWarnings(uint32 timeLeft) const;
[[nodiscard]] uint32 GetMaxPlayers() const;
@@ -778,7 +796,7 @@ public:
bool AddPlayerToMap(Player*) override;
void RemovePlayerFromMap(Player*, bool) override;
bool CanEnter(Player* player, bool loginCheck = false) override;
EnterState CannotEnter(Player* player, bool loginCheck = false) override;
void SetUnload();
//void UnloadAll(bool pForce);
void RemoveAllPlayers() override;

View File

@@ -266,8 +266,8 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator& itr)
return true;
}
bool MapInstanced::CanEnter(Player* /*player*/, bool /*loginCheck*/)
Map::EnterState MapInstanced::CannotEnter(Player* /*player*/, bool /*loginCheck*/)
{
//ABORT();
return true;
return CAN_ENTER;
}

View File

@@ -25,7 +25,7 @@ public:
void DelayedUpdate(const uint32 diff) override;
//void RelocationNotify();
void UnloadAll() override;
bool CanEnter(Player* player, bool loginCheck = false) override;
EnterState CannotEnter(Player* player, bool loginCheck = false) override;
Map* CreateInstanceForPlayer(const uint32 mapId, Player* player);
Map* FindInstanceMap(uint32 instanceId) const

View File

@@ -122,18 +122,18 @@ Map* MapManager::FindMap(uint32 mapid, uint32 instanceId) const
return ((MapInstanced*)map)->FindInstanceMap(instanceId);
}
bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
Map::EnterState MapManager::PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck)
{
MapEntry const* entry = sMapStore.LookupEntry(mapid);
if (!entry)
return false;
return Map::CANNOT_ENTER_NO_ENTRY;
if (!entry->IsDungeon())
return true;
return Map::CAN_ENTER;
InstanceTemplate const* instance = sObjectMgr->GetInstanceTemplate(mapid);
if (!instance)
return false;
return Map::CANNOT_ENTER_UNINSTANCED_DUNGEON;
Difficulty targetDifficulty, requestedDifficulty;
targetDifficulty = requestedDifficulty = player->GetDifficulty(entry->IsRaid());
@@ -142,17 +142,17 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
if (!mapDiff)
{
player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, requestedDifficulty);
return false;
return Map::CANNOT_ENTER_DIFFICULTY_UNAVAILABLE;
}
//Bypass checks for GMs
if (player->IsGameMaster())
return true;
return Map::CAN_ENTER;
char const* mapName = entry->name[player->GetSession()->GetSessionDbcLocale()];
if (!sScriptMgr->CanEnterMap(player, entry, instance, mapDiff, loginCheck))
return false;
return Map::CANNOT_ENTER_UNSPECIFIED_REASON;
Group* group = player->GetGroup();
if (entry->IsRaid())
@@ -164,7 +164,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
// TODO: this is not a good place to send the message
player->GetSession()->SendAreaTriggerMessage(player->GetSession()->GetAcoreString(LANG_INSTANCE_RAID_GROUP_ONLY), mapName);
LOG_DEBUG("maps", "MAP: Player '%s' must be in a raid group to enter instance '%s'", player->GetName().c_str(), mapName);
return false;
return Map::CANNOT_ENTER_NOT_IN_RAID;
}
}
@@ -174,7 +174,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
if (!sLFGMgr->inLfgDungeonMap(group->GetGUID(), mapid, targetDifficulty))
{
player->SendTransferAborted(mapid, TRANSFER_ABORT_MAP_NOT_ALLOWED);
return false;
return Map::CANNOT_ENTER_UNSPECIFIED_REASON;
}
if (!player->IsAlive())
@@ -197,13 +197,13 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
WorldPacket data(SMSG_CORPSE_NOT_IN_INSTANCE, 0);
player->GetSession()->SendPacket(&data);
LOG_DEBUG("maps", "MAP: Player '%s' does not have a corpse in instance '%s' and cannot enter.", player->GetName().c_str(), mapName);
return false;
return Map::CANNOT_ENTER_CORPSE_IN_DIFFERENT_INSTANCE;
}
LOG_DEBUG("maps", "MAP: Player '%s' has corpse in instance '%s' and can enter.", player->GetName().c_str(), mapName);
}
else
{
LOG_DEBUG("maps", "Map::CanPlayerEnter - player '%s' is dead but does not have a corpse!", player->GetName().c_str());
LOG_DEBUG("maps", "Map::PlayerCannotEnter - player '%s' is dead but does not have a corpse!", player->GetName().c_str());
}
}
@@ -213,8 +213,8 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
uint32 destInstId = sInstanceSaveMgr->PlayerGetDestinationInstanceId(player, mapid, targetDifficulty);
if (destInstId)
if (Map* boundMap = sMapMgr->FindMap(mapid, destInstId))
if (!boundMap->CanEnter(player, loginCheck))
return false;
if (Map::EnterState denyReason = boundMap->CannotEnter(player, loginCheck))
return denyReason;
}
// players are only allowed to enter 5 instances per hour
@@ -228,12 +228,12 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
if (!player->CheckInstanceCount(instaceIdToCheck) && !player->isDead())
{
player->SendTransferAborted(mapid, TRANSFER_ABORT_TOO_MANY_INSTANCES);
return false;
return Map::CANNOT_ENTER_TOO_MANY_INSTANCES;
}
}
//Other requirements
return player->Satisfy(sObjectMgr->GetAccessRequirement(mapid, targetDifficulty), mapid, true);
return player->Satisfy(sObjectMgr->GetAccessRequirement(mapid, targetDifficulty), mapid, true) ? Map::CAN_ENTER : Map::CANNOT_ENTER_UNSPECIFIED_REASON;
}
void MapManager::Update(uint32 diff)

View File

@@ -119,7 +119,7 @@ public:
void DoDelayedMovesAndRemoves();
bool CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck = false);
Map::EnterState PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck = false);
void InitializeVisibilityDistanceInfo();
/* statistics */

View File

@@ -1191,7 +1191,7 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/)
uint32 mapid = destTarget->GetMapId();
float x, y, z, orientation;
destTarget->GetPosition(x, y, z, orientation);
target->TeleportTo(mapid, x, y, z, orientation, TELE_TO_GM_MODE); // skip CanPlayerEnter check
target->TeleportTo(mapid, x, y, z, orientation, TELE_TO_GM_MODE); // skip PlayerCannotEnter check
}
return;
}