aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Maps
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2015-12-31 19:51:07 +0100
committerShauren <shauren.trinity@gmail.com>2016-03-21 19:41:28 +0100
commit7422557d03b3cbb5b00a39b16c52f879c2f31fdd (patch)
treec379a50a7ba112b8a4f5149f6c89973939a8675d /src/server/game/Maps
parent96ca739a0b0d2b34a28fbac0593e076fb3c42f1b (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.cpp60
-rw-r--r--src/server/game/Maps/Map.h22
-rw-r--r--src/server/game/Maps/MapInstanced.cpp31
-rw-r--r--src/server/game/Maps/MapInstanced.h6
-rw-r--r--src/server/game/Maps/MapManager.cpp64
-rw-r--r--src/server/game/Maps/MapManager.h4
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 */