diff options
| author | Treeston <treeston.mmoc@gmail.com> | 2015-12-31 19:51:07 +0100 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2016-03-21 19:41:28 +0100 |
| commit | 7422557d03b3cbb5b00a39b16c52f879c2f31fdd (patch) | |
| tree | c379a50a7ba112b8a4f5149f6c89973939a8675d /src/server/game/Maps | |
| parent | 96ca739a0b0d2b34a28fbac0593e076fb3c42f1b (diff) | |
Merge pull request #16110 from Treeston/3.3.5-instancerevive
Game/Maps: Clean up instance zone-in handling
(cherry picked from commit eb3dc8a4f064d89b78248a511bcf67f805ea3314)
Diffstat (limited to 'src/server/game/Maps')
| -rw-r--r-- | src/server/game/Maps/Map.cpp | 60 | ||||
| -rw-r--r-- | src/server/game/Maps/Map.h | 22 | ||||
| -rw-r--r-- | src/server/game/Maps/MapInstanced.cpp | 31 | ||||
| -rw-r--r-- | src/server/game/Maps/MapInstanced.h | 6 | ||||
| -rw-r--r-- | src/server/game/Maps/MapManager.cpp | 64 | ||||
| -rw-r--r-- | src/server/game/Maps/MapManager.h | 4 |
6 files changed, 81 insertions, 106 deletions
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 90c02b10477..3dbed19fc98 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -3062,62 +3062,38 @@ void InstanceMap::InitVisibilityDistance() /* Do map specific checks to see if the player can enter */ -bool InstanceMap::CanEnter(Player* player) +Map::EnterState InstanceMap::CannotEnter(Player* player) { if (player->GetMapRef().getTarget() == this) { - TC_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()); + TC_LOG_ERROR("maps", "InstanceMap::CannotEnter - 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); + return Map::CannotEnter(player); // cannot enter if the instance is full (player cap), GMs don't count uint32 maxPlayers = GetMaxPlayers(); if (GetPlayersCountExceptGMs() >= maxPlayers) { TC_LOG_WARN("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 - // allow if just loading + // cannot enter while an encounter is in progress (unless this is a relog, in which case it is permitted) if (!player->IsLoading() && IsRaid() && GetInstanceScript() && GetInstanceScript()->IsEncounterInProgress()) - { - player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT); - return false; - } + return CANNOT_ENTER_ZONE_IN_COMBAT; - // cannot enter if instance is in use by another party/soloer that have a - // permanent save in the same instance id + // cannot enter if player is permanent saved to a different instance id + if (InstancePlayerBind* playerBind = player->GetBoundInstance(GetId(), GetDifficultyID())) + if (playerBind->perm && playerBind->save) + if (playerBind->save->GetInstanceId() != GetInstanceId()) + return CANNOT_ENTER_INSTANCE_BIND_MISMATCH; - PlayerList const &playerList = GetPlayers(); - - if (!playerList.isEmpty()) - for (PlayerList::const_iterator i = playerList.begin(); i != playerList.end(); ++i) - if (Player* iPlayer = i->GetSource()) - { - if (iPlayer->IsGameMaster()) // bypass GMs - continue; - if (!player->GetGroup()) // player has not group and there is someone inside, deny entry - { - player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS); - return false; - } - // 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; - } - break; - } - - return Map::CanEnter(player); + return Map::CannotEnter(player); } /* @@ -3474,21 +3450,21 @@ void BattlegroundMap::InitVisibilityDistance() m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodInBGArenas(); } -bool BattlegroundMap::CanEnter(Player* player) +Map::EnterState BattlegroundMap::CannotEnter(Player* player) { if (player->GetMapRef().getTarget() == this) { - TC_LOG_ERROR("maps", "BGMap::CanEnter - %s is already in map!", player->GetGUID().ToString().c_str()); + TC_LOG_ERROR("maps", "BGMap::CannotEnter - 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; // player number limit is checked in bgmgr, no need to do it here - return Map::CanEnter(player); + return Map::CannotEnter(player); } bool BattlegroundMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 34aa00e4bf9..d51f05bc32a 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -365,7 +365,23 @@ class Map : public GridRefManager<NGridType> uint32 GetInstanceId() const { return i_InstanceId; } uint8 GetSpawnMode() const { return (i_spawnMode); } - virtual bool CanEnter(Player* /*player*/) { 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*/) { return CAN_ENTER; } const char* GetMapName() const; // have meaning only for instanced map (that have set real difficulty) @@ -751,7 +767,7 @@ class InstanceMap : public Map InstanceScript* GetInstanceScript() { return i_data; } void PermBindAllPlayers(Player* source); void UnloadAll() override; - bool CanEnter(Player* player) override; + EnterState CannotEnter(Player* player) override; void SendResetWarnings(uint32 timeLeft) const; void SetResetSchedule(bool on); @@ -774,7 +790,7 @@ class BattlegroundMap : public Map bool AddPlayerToMap(Player* player, bool initPlayer = true) override; void RemovePlayerFromMap(Player*, bool) override; - bool CanEnter(Player* player) override; + EnterState CannotEnter(Player* player) override; void SetUnload(); //void UnloadAll(bool pForce); void RemoveAllPlayers() override; diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 70623e1d7ab..4c065f836b9 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -111,12 +111,12 @@ void MapInstanced::UnloadAll() - create the instance if it's not created already - the player is not actually added to the instance (only in InstanceMap::Add) */ -Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player) +Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player, uint32 loginInstanceId) { if (GetId() != mapId || !player) - return NULL; + return nullptr; - Map* map = NULL; + Map* map = nullptr; uint32 newInstanceId = 0; // instanceId of the resulting map if (IsBattlegroundOrArena()) @@ -125,7 +125,7 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player) // the instance id is set in battlegroundid newInstanceId = player->GetBattlegroundId(); if (!newInstanceId) - return NULL; + return nullptr; map = sMapMgr->FindMap(mapId, newInstanceId); if (!map) @@ -135,20 +135,29 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player) else { player->TeleportToBGEntryPoint(); - return NULL; + return nullptr; } } } else if (!IsGarrison()) { InstancePlayerBind* pBind = player->GetBoundInstance(GetId(), player->GetDifficultyID(GetEntry())); - InstanceSave* pSave = pBind ? pBind->save : NULL; + InstanceSave* pSave = pBind ? pBind->save : nullptr; - // the player's permanent player bind is taken into consideration first - // then the player's group bind and finally the solo bind. + // priority: + // 1. player's permanent bind + // 2. player's current instance id if this is at login + // 3. group's current bind + // 4. player's current bind if (!pBind || !pBind->perm) { - InstanceGroupBind* groupBind = NULL; + if (loginInstanceId) // if the player has a saved instance id on login, we either use this instance or relocate him out (return null) + { + map = FindInstanceMap(loginInstanceId); + return (map && map->GetId() == GetId()) ? map : nullptr; // is this check necessary? or does MapInstanced only find instances of itself? + } + + InstanceGroupBind* groupBind = nullptr; Group* group = player->GetGroup(); // use the player's difficulty setting (it may not be the same as the group's) if (group) @@ -288,8 +297,8 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) return true; } -bool MapInstanced::CanEnter(Player* /*player*/) +Map::EnterState MapInstanced::CannotEnter(Player* /*player*/) { //ABORT(); - return true; + return CAN_ENTER; } diff --git a/src/server/game/Maps/MapInstanced.h b/src/server/game/Maps/MapInstanced.h index f0d185bd796..4fb334cb0ce 100644 --- a/src/server/game/Maps/MapInstanced.h +++ b/src/server/game/Maps/MapInstanced.h @@ -39,13 +39,13 @@ class MapInstanced : public Map void DelayedUpdate(const uint32 diff) override; //void RelocationNotify(); void UnloadAll() override; - bool CanEnter(Player* player) override; + EnterState CannotEnter(Player* /*player*/) override; - Map* CreateInstanceForPlayer(const uint32 mapId, Player* player); + Map* CreateInstanceForPlayer(const uint32 mapId, Player* player, uint32 loginInstanceId=0); Map* FindInstanceMap(uint32 instanceId) const { InstancedMaps::const_iterator i = m_InstancedMaps.find(instanceId); - return(i == m_InstancedMaps.end() ? NULL : i->second); + return(i == m_InstancedMaps.end() ? nullptr : i->second); } bool DestroyInstance(InstancedMaps::iterator &itr); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 81302671762..184af8fc360 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -103,12 +103,12 @@ Map* MapManager::FindBaseNonInstanceMap(uint32 mapId) const return map; } -Map* MapManager::CreateMap(uint32 id, Player* player) +Map* MapManager::CreateMap(uint32 id, Player* player, uint32 loginInstanceId) { Map* m = CreateBaseMap(id); if (m && m->Instanceable()) - m = ((MapInstanced*)m)->CreateInstanceForPlayer(id, player); + m = ((MapInstanced*)m)->CreateInstanceForPlayer(id, player, loginInstanceId); return m; } @@ -125,47 +125,36 @@ 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->GetDifficultyID(entry); // Get the highest available difficulty if current setting is higher than the instance allows MapDifficultyEntry const* mapDiff = GetDownscaledMapDifficultyData(entry->ID, targetDifficulty); 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->MapName_lang; Group* group = player->GetGroup(); - if (entry->IsRaid()) - { - // can only enter in a raid group + if (entry->IsRaid()) // can only enter in a raid group if ((!group || !group->isRaidGroup()) && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID)) - { - /// @todo this is not a good place to send the message - player->SendRaidGroupOnlyMessage(RAID_GROUP_ERR_ONLY, 0); - TC_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; if (!player->IsAlive()) { @@ -183,12 +172,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck) } while (corpseMap); if (!corpseMap) - { - WorldPackets::Misc::AreaTriggerNoCorpse packet; - player->GetSession()->SendPacket(packet.Write()); - TC_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; TC_LOG_DEBUG("maps", "MAP: Player '%s' has corpse in instance '%s' and can enter.", player->GetName().c_str(), mapName); } @@ -197,23 +181,13 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck) } //Get instance where player's group is bound & its map - if (group) + if (!loginCheck && group) { InstanceGroupBind* boundInstance = group->GetBoundInstance(entry); if (boundInstance && boundInstance->save) if (Map* boundMap = sMapMgr->FindMap(mapid, boundInstance->save->GetInstanceId())) - if (!loginCheck && !boundMap->CanEnter(player)) - return false; - /* - This check has to be moved to InstanceMap::CanEnter() - // Player permanently bounded to different instance than groups one - InstancePlayerBind* playerBoundedInstance = player->GetBoundInstance(mapid, player->GetDifficultyID(entry)); - if (playerBoundedInstance && playerBoundedInstance->perm && playerBoundedInstance->save && - boundedInstance->save->GetInstanceId() != playerBoundedInstance->save->GetInstanceId()) - { - /// @todo send some kind of error message to the player - return false; - }*/ + if (Map::EnterState denyReason = boundMap->CannotEnter(player)) + return denyReason; } // players are only allowed to enter 5 instances per hour @@ -225,14 +199,14 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck) // instanceId can never be 0 - will not be found if (!player->CheckInstanceCount(instanceIdToCheck) && !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); + if (player->Satisfy(sObjectMgr->GetAccessRequirement(mapid, targetDifficulty), mapid, true)) + return Map::CAN_ENTER; + else + return Map::CANNOT_ENTER_UNSPECIFIED_REASON; } void MapManager::Update(uint32 diff) diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index 24cbbf4ef4d..5d679cbe4d9 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -35,7 +35,7 @@ class MapManager Map* CreateBaseMap(uint32 mapId); Map* FindBaseNonInstanceMap(uint32 mapId) const; - Map* CreateMap(uint32 mapId, Player* player); + Map* CreateMap(uint32 mapId, Player* player, uint32 loginInstanceId=0); Map* FindMap(uint32 mapId, uint32 instanceId) const; uint32 GetAreaId(uint32 mapid, float x, float y, float z) const @@ -102,7 +102,7 @@ class MapManager void DoDelayedMovesAndRemoves(); - bool CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck = false); + Map::EnterState PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck = false); void InitializeVisibilityDistanceInfo(); /* statistics */ |
