diff options
Diffstat (limited to 'src/server/game/Maps/Map.cpp')
-rw-r--r-- | src/server/game/Maps/Map.cpp | 272 |
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); } |