aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Maps/Map.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Maps/Map.cpp')
-rw-r--r--src/server/game/Maps/Map.cpp272
1 files changed, 162 insertions, 110 deletions
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 440fe34bc70..1810b63d555 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -32,10 +32,10 @@
#include "GridStates.h"
#include "Group.h"
#include "InstancePackets.h"
+#include "InstanceSaveMgr.h"
#include "InstanceScenario.h"
#include "InstanceScript.h"
#include "Log.h"
-#include "MapInstanced.h"
#include "MapManager.h"
#include "Metric.h"
#include "MiscPackets.h"
@@ -126,7 +126,7 @@ void Map::DeleteStateMachine()
delete si_GridStates[GRID_STATE_REMOVAL];
}
-Map::Map(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode, Map* /*_parent*/) :
+Map::Map(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode) :
_creatureToMoveLock(false), _gameObjectsToMoveLock(false), _dynamicObjectsToMoveLock(false), _areaTriggersToMoveLock(false),
i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId),
m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE),
@@ -309,15 +309,9 @@ void Map::DeleteFromWorld(Player* player)
delete player;
}
-void Map::EnsureGridCreated(GridCoord const& p)
-{
- std::lock_guard<std::mutex> lock(_gridLock);
- EnsureGridCreated_i(p);
-}
-
//Create NGrid so the object can be added to it
//But object data is not loaded here
-void Map::EnsureGridCreated_i(GridCoord const& p)
+void Map::EnsureGridCreated(GridCoord const& p)
{
if (!getNGrid(p.x_coord, p.y_coord))
{
@@ -1760,6 +1754,86 @@ bool Map::getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, floa
return result;
}
+Map::EnterState Map::PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck)
+{
+ MapEntry const* entry = sMapStore.LookupEntry(mapid);
+ if (!entry)
+ return CANNOT_ENTER_NO_ENTRY;
+
+ if (!entry->IsDungeon())
+ return CAN_ENTER;
+
+ 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 = sDB2Manager.GetDownscaledMapDifficultyData(mapid, targetDifficulty);
+ if (!mapDiff)
+ return CANNOT_ENTER_DIFFICULTY_UNAVAILABLE;
+
+ //Bypass checks for GMs
+ if (player->IsGameMaster())
+ return CAN_ENTER;
+
+ //Other requirements
+ if (!player->Satisfy(sObjectMgr->GetAccessRequirement(mapid, targetDifficulty), mapid, true))
+ return CANNOT_ENTER_UNSPECIFIED_REASON;
+
+ char const* mapName = entry->MapName[sWorld->GetDefaultDbcLocale()];
+
+ Group* group = player->GetGroup();
+ if (entry->IsRaid() && entry->Expansion() >= sWorld->getIntConfig(CONFIG_EXPANSION)) // can only enter in a raid group but raids from old expansion don't need a group
+ if ((!group || !group->isRaidGroup()) && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID))
+ return CANNOT_ENTER_NOT_IN_RAID;
+
+ if (!player->IsAlive())
+ {
+ if (player->HasCorpse())
+ {
+ // let enter in ghost mode in instance that connected to inner instance with corpse
+ uint32 corpseMap = player->GetCorpseLocation().GetMapId();
+ do
+ {
+ if (corpseMap == mapid)
+ break;
+
+ InstanceTemplate const* corpseInstance = sObjectMgr->GetInstanceTemplate(corpseMap);
+ corpseMap = corpseInstance ? corpseInstance->Parent : 0;
+ } while (corpseMap);
+
+ if (!corpseMap)
+ return 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);
+ }
+ else
+ TC_LOG_DEBUG("maps", "Map::CanPlayerEnter - player '%s' is dead but does not have a corpse!", player->GetName().c_str());
+ }
+
+ //Get instance where player's group is bound & its map
+ if (!loginCheck && group)
+ {
+ InstanceGroupBind* boundInstance = group->GetBoundInstance(entry);
+ if (boundInstance && boundInstance->save)
+ if (Map* boundMap = sMapMgr->FindMap(mapid, boundInstance->save->GetInstanceId()))
+ if (EnterState denyReason = boundMap->CannotEnter(player))
+ return denyReason;
+ }
+
+ // players are only allowed to enter 5 instances per hour
+ if (entry->IsDungeon() && (!player->GetGroup() || (player->GetGroup() && !player->GetGroup()->isLFGGroup())))
+ {
+ uint32 instanceIdToCheck = 0;
+ if (InstanceSave* save = player->GetInstanceSave(mapid))
+ instanceIdToCheck = save->GetInstanceId();
+
+ // instanceId can never be 0 - will not be found
+ if (!player->CheckInstanceCount(instanceIdToCheck) && !player->isDead())
+ return CANNOT_ENTER_TOO_MANY_INSTANCES;
+ }
+
+ return CAN_ENTER;
+}
+
char const* Map::GetMapName() const
{
return i_mapEntry->MapName[sWorld->GetDefaultDbcLocale()];
@@ -2695,8 +2769,8 @@ template TC_GAME_API void Map::RemoveFromMap(Conversation*, bool);
/* ******* Dungeon Instance Maps ******* */
-InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode, Map* _parent, TeamId InstanceTeam)
- : Map(id, expiry, InstanceId, SpawnMode, _parent),
+InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode, TeamId InstanceTeam)
+ : Map(id, expiry, InstanceId, SpawnMode),
m_resetAfterUnload(false), m_unloadWhenEmpty(false),
i_data(nullptr), i_script_id(0), i_script_team(InstanceTeam), i_scenario(nullptr)
{
@@ -2763,112 +2837,97 @@ Map::EnterState InstanceMap::CannotEnter(Player* player)
*/
bool InstanceMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
{
- /// @todo Not sure about checking player level: already done in HandleAreaTriggerOpcode
- // GMs still can teleport player in instance.
- // Is it needed?
-
- {
- std::lock_guard<std::mutex> lock(_mapLock);
- // Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
- //if (!CanEnter(player))
- //return false;
-
- // Dungeon only code
- if (IsDungeon())
- {
- Group* group = player->GetGroup();
+ Group* group = player->GetGroup();
- // increase current instances (hourly limit)
- if (!group || !group->isLFGGroup())
- player->AddInstanceEnterTime(GetInstanceId(), GameTime::GetGameTime());
+ // increase current instances (hourly limit)
+ if (!group || !group->isLFGGroup())
+ player->AddInstanceEnterTime(GetInstanceId(), GameTime::GetGameTime());
- // get or create an instance save for the map
- InstanceSave* mapSave = sInstanceSaveMgr->GetInstanceSave(GetInstanceId());
- if (!mapSave)
- {
- TC_LOG_DEBUG("maps", "InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetDifficultyID(), GetInstanceId());
- mapSave = sInstanceSaveMgr->AddInstanceSave(GetId(), GetInstanceId(), GetDifficultyID(), 0, 0, true);
- }
+ // get or create an instance save for the map
+ InstanceSave* mapSave = sInstanceSaveMgr->GetInstanceSave(GetInstanceId());
+ if (!mapSave)
+ {
+ TC_LOG_DEBUG("maps", "InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetDifficultyID(), GetInstanceId());
+ mapSave = sInstanceSaveMgr->AddInstanceSave(GetId(), GetInstanceId(), GetDifficultyID(), 0, 0, true);
+ }
- ASSERT(mapSave);
+ ASSERT(mapSave);
- // check for existing instance binds
- InstancePlayerBind* playerBind = player->GetBoundInstance(GetId(), GetDifficultyID());
- if (playerBind && playerBind->perm)
+ // check for existing instance binds
+ InstancePlayerBind* playerBind = player->GetBoundInstance(GetId(), GetDifficultyID());
+ if (playerBind && playerBind->perm)
+ {
+ // cannot enter other instances if bound permanently
+ if (playerBind->save != mapSave)
+ {
+ TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is permanently bound to instance %s %d, %d, %d, %d, %d, %d but he is being put into instance %s %d, %d, %d, %d, %d, %d", player->GetName().c_str(), player->GetGUID().ToString().c_str(), GetMapName(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficultyID()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset());
+ return false;
+ }
+ }
+ else
+ {
+ if (group)
+ {
+ // solo saves should have been reset when the map was loaded
+ InstanceGroupBind* groupBind = group->GetBoundInstance(this);
+ if (playerBind && playerBind->save != mapSave)
{
- // cannot enter other instances if bound permanently
- if (playerBind->save != mapSave)
- {
- TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is permanently bound to instance %s %d, %d, %d, %d, %d, %d but he is being put into instance %s %d, %d, %d, %d, %d, %d", player->GetName().c_str(), player->GetGUID().ToString().c_str(), GetMapName(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficultyID()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset());
- return false;
- }
+ TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is being put into instance %s %d, %d, %d, %d, %d, %d but he is in group %s and is bound to instance %d, %d, %d, %d, %d, %d!", player->GetName().c_str(), player->GetGUID().ToString().c_str(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), group->GetLeaderGUID().ToString().c_str(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficultyID()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
+ if (groupBind)
+ TC_LOG_ERROR("maps", "InstanceMap::Add: the group is bound to the instance %s %d, %d, %d, %d, %d, %d", GetMapName(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficultyID()), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
+ //ABORT();
+ return false;
}
+ // bind to the group or keep using the group save
+ if (!groupBind)
+ group->BindToInstance(mapSave, false);
else
{
- if (group)
+ // cannot jump to a different instance without resetting it
+ if (groupBind->save != mapSave)
{
- // solo saves should have been reset when the map was loaded
- InstanceGroupBind* groupBind = group->GetBoundInstance(this);
- if (playerBind && playerBind->save != mapSave)
- {
- TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is being put into instance %s %d, %d, %d, %d, %d, %d but he is in group %s and is bound to instance %d, %d, %d, %d, %d, %d!", player->GetName().c_str(), player->GetGUID().ToString().c_str(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), group->GetLeaderGUID().ToString().c_str(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficultyID()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
- if (groupBind)
- TC_LOG_ERROR("maps", "InstanceMap::Add: the group is bound to the instance %s %d, %d, %d, %d, %d, %d", GetMapName(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficultyID()), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
- //ABORT();
- return false;
- }
- // bind to the group or keep using the group save
- if (!groupBind)
- group->BindToInstance(mapSave, false);
+ TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is being put into instance %d, %d, %d but he is in group %s which is bound to instance %d, %d, %d!", player->GetName().c_str(), player->GetGUID().ToString().c_str(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), group->GetLeaderGUID().ToString().c_str(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficultyID()));
+ TC_LOG_ERROR("maps", "MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount());
+ if (groupBind->save)
+ TC_LOG_ERROR("maps", "GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
else
- {
- // cannot jump to a different instance without resetting it
- if (groupBind->save != mapSave)
- {
- TC_LOG_ERROR("maps", "InstanceMap::Add: player %s %s is being put into instance %d, %d, %d but he is in group %s which is bound to instance %d, %d, %d!", player->GetName().c_str(), player->GetGUID().ToString().c_str(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), group->GetLeaderGUID().ToString().c_str(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficultyID()));
- TC_LOG_ERROR("maps", "MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount());
- if (groupBind->save)
- TC_LOG_ERROR("maps", "GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
- else
- TC_LOG_ERROR("maps", "GroupBind save NULL");
- return false;
- }
- // if the group/leader is permanently bound to the instance
- // players also become permanently bound when they enter
- if (groupBind->perm)
- {
- WorldPackets::Instance::PendingRaidLock pendingRaidLock;
- pendingRaidLock.TimeUntilLock = 60000;
- pendingRaidLock.CompletedMask = i_data ? i_data->GetCompletedEncounterMask() : 0;
- pendingRaidLock.Extending = false;
- pendingRaidLock.WarningOnly = false; // events it throws: 1 : INSTANCE_LOCK_WARNING 0 : INSTANCE_LOCK_STOP / INSTANCE_LOCK_START
- player->SendDirectMessage(pendingRaidLock.Write());
- player->SetPendingBind(mapSave->GetInstanceId(), 60000);
- }
- }
+ TC_LOG_ERROR("maps", "GroupBind save NULL");
+ return false;
}
- else
+ // if the group/leader is permanently bound to the instance
+ // players also become permanently bound when they enter
+ if (groupBind->perm)
{
- // set up a solo bind or continue using it
- if (!playerBind)
- player->BindToInstance(mapSave, false);
- else
- // cannot jump to a different instance without resetting it
- ASSERT(playerBind->save == mapSave);
+ WorldPackets::Instance::PendingRaidLock pendingRaidLock;
+ pendingRaidLock.TimeUntilLock = 60000;
+ pendingRaidLock.CompletedMask = i_data ? i_data->GetCompletedEncounterMask() : 0;
+ pendingRaidLock.Extending = false;
+ pendingRaidLock.WarningOnly = false; // events it throws: 1 : INSTANCE_LOCK_WARNING 0 : INSTANCE_LOCK_STOP / INSTANCE_LOCK_START
+ player->SendDirectMessage(pendingRaidLock.Write());
+ player->SetPendingBind(mapSave->GetInstanceId(), 60000);
}
}
}
+ else
+ {
+ // set up a solo bind or continue using it
+ if (!playerBind)
+ player->BindToInstance(mapSave, false);
+ else
+ // cannot jump to a different instance without resetting it
+ ASSERT(playerBind->save == mapSave);
+ }
+ }
- // for normal instances cancel the reset schedule when the
- // first player enters (no players yet)
- SetResetSchedule(false);
+ // for normal instances cancel the reset schedule when the
+ // first player enters (no players yet)
+ SetResetSchedule(false);
- TC_LOG_DEBUG("maps", "MAP: Player '%s' entered instance '%u' of map '%s'", player->GetName().c_str(), GetInstanceId(), GetMapName());
- // initialize unload state
- m_unloadTimer = 0;
- m_resetAfterUnload = false;
- m_unloadWhenEmpty = false;
- }
+ TC_LOG_DEBUG("maps", "MAP: Player '%s' entered instance '%u' of map '%s'", player->GetName().c_str(), GetInstanceId(), GetMapName());
+ // initialize unload state
+ m_unloadTimer = 0;
+ m_resetAfterUnload = false;
+ m_unloadWhenEmpty = false;
// this will acquire the same mutex so it cannot be in the previous block
Map::AddPlayerToMap(player, initPlayer);
@@ -3213,8 +3272,8 @@ uint32 InstanceMap::GetMaxResetDelay() const
/* ******* Battleground Instance Maps ******* */
-BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, Difficulty spawnMode)
- : Map(id, expiry, InstanceId, spawnMode, _parent), m_bg(nullptr)
+BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Difficulty spawnMode)
+ : Map(id, expiry, InstanceId, spawnMode), m_bg(nullptr)
{
//lets initialize visibility distance for BG/Arenas
BattlegroundMap::InitVisibilityDistance();
@@ -3256,14 +3315,7 @@ Map::EnterState BattlegroundMap::CannotEnter(Player* player)
bool BattlegroundMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
{
- {
- std::lock_guard<std::mutex> lock(_mapLock);
- //Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
- //if (!CanEnter(player))
- //return false;
- // reset instance validity, battleground maps do not homebind
- player->m_InstanceValid = true;
- }
+ player->m_InstanceValid = true;
return Map::AddPlayerToMap(player, initPlayer);
}