aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2020-01-11 12:49:50 +0100
committerShauren <shauren.trinity@gmail.com>2022-10-04 00:19:38 +0200
commitddd0c7b152d65b980db0cc2d00f15ae62a602936 (patch)
tree475eeed3e0e514cd480e87133a590dd0de4c2064 /src/server
parent76be303351ae398b7f9e69e4c472cb5b05fce45e (diff)
Core/Instances: Reimplement resetting instances from UI
Diffstat (limited to 'src/server')
-rw-r--r--src/server/game/Entities/Player/Player.cpp43
-rw-r--r--src/server/game/Entities/Player/Player.h4
-rw-r--r--src/server/game/Groups/Group.cpp40
-rw-r--r--src/server/game/Groups/Group.h4
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp93
-rw-r--r--src/server/game/Maps/Map.cpp90
-rw-r--r--src/server/game/Maps/Map.h29
-rw-r--r--src/server/game/Maps/MapManager.cpp4
8 files changed, 159 insertions, 148 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 61efb379d2a..acc9a53f9f9 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -17400,6 +17400,11 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
// flight will started later
}
}
+ else if (mapEntry->IsDungeon() && instanceId)
+ {
+ // try finding instance by id first
+ map = sMapMgr->FindMap(mapId, instanceId);
+ }
// Map could be changed before
mapEntry = sMapStore.LookupEntry(mapId);
@@ -17447,6 +17452,9 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
case Map::CANNOT_ENTER_ZONE_IN_COMBAT:
SendTransferAborted(map->GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
break;
+ case Map::CANNOT_ENTER_INSTANCE_SHUTTING_DOWN:
+ SendTransferAborted(map->GetId(), TRANSFER_ABORT_NOT_FOUND);
+ break;
default:
break;
}
@@ -20589,8 +20597,41 @@ void Player::SendResetFailedNotify(uint32 /*mapid*/) const
}
/// Reset all solo instances and optionally send a message on success for each
-void Player::ResetInstances(InstanceResetMethod /*method*/, bool /*isRaid*/, bool /*isLegacy*/)
+void Player::ResetInstances(InstanceResetMethod method)
{
+ for (auto itr = m_recentInstances.begin(); itr != m_recentInstances.end(); )
+ {
+ Map* map = sMapMgr->FindMap(itr->first, itr->second);
+ bool forgetInstance = false;
+ if (map)
+ {
+ if (InstanceMap* instance = map->ToInstanceMap())
+ {
+ switch (instance->Reset(method))
+ {
+ case InstanceResetResult::Success:
+ SendResetInstanceSuccess(map->GetId());
+ forgetInstance = true;
+ break;
+ case InstanceResetResult::NotEmpty:
+ if (method == InstanceResetMethod::Manual)
+ SendResetInstanceFailed(INSTANCE_RESET_FAILED, map->GetId());
+ else if (method == InstanceResetMethod::OnChangeDifficulty)
+ forgetInstance = true;
+ break;
+ case InstanceResetResult::CannotReset:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (forgetInstance)
+ itr = m_recentInstances.erase(itr);
+ else
+ ++itr;
+ }
}
void Player::SendResetInstanceSuccess(uint32 MapId) const
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 64f12463459..aba0480d681 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -92,6 +92,8 @@ class SpellCastTargets;
class TradeData;
enum GroupCategory : uint8;
+enum class InstanceResetMethod : uint8;
+enum class InstanceResetResult : uint8;
enum InventoryType : uint8;
enum ItemClass : uint8;
enum LootError : uint8;
@@ -2085,7 +2087,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SendDungeonDifficulty(int32 forcedDifficulty = -1) const;
void SendRaidDifficulty(bool legacy, int32 forcedDifficulty = -1) const;
- void ResetInstances(InstanceResetMethod method, bool isRaid, bool isLegacy);
+ void ResetInstances(InstanceResetMethod method);
void SendResetInstanceSuccess(uint32 MapId) const;
void SendResetInstanceFailed(ResetFailedReason reason, uint32 mapID) const;
void SendResetFailedNotify(uint32 mapid) const;
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index c799212b059..11f07340955 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -481,12 +481,6 @@ bool Group::AddMember(Player* player)
if (!IsLeader(player->GetGUID()) && !isBGGroup() && !isBFGroup())
{
- // reset the new member's instances, unless he is currently in one of them
- // including raid/heroic instances that they are not permanently bound to!
- player->ResetInstances(INSTANCE_RESET_GROUP_JOIN, false, false);
- player->ResetInstances(INSTANCE_RESET_GROUP_JOIN, true, false);
- player->ResetInstances(INSTANCE_RESET_GROUP_JOIN, true, true);
-
if (player->GetDungeonDifficultyID() != GetDungeonDifficultyID())
{
player->SetDungeonDifficultyID(GetDungeonDifficultyID());
@@ -768,15 +762,11 @@ void Group::Disband(bool hideDestroy /* = false */)
stmt->setUInt32(0, m_dbStoreId);
trans->Append(stmt);
- CharacterDatabase.CommitTransaction(trans);
-
- ResetInstances(INSTANCE_RESET_GROUP_DISBAND, false, false, nullptr);
- ResetInstances(INSTANCE_RESET_GROUP_DISBAND, true, false, nullptr);
- ResetInstances(INSTANCE_RESET_GROUP_DISBAND, true, true, nullptr);
-
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_LFG_DATA);
stmt->setUInt32(0, m_dbStoreId);
- CharacterDatabase.Execute(stmt);
+ trans->Append(stmt);
+
+ CharacterDatabase.CommitTransaction(trans);
sGroupMgr->FreeGroupDbStoreId(this);
}
@@ -1359,8 +1349,30 @@ Difficulty Group::GetDifficultyID(MapEntry const* mapEntry) const
return m_raidDifficulty;
}
-void Group::ResetInstances(InstanceResetMethod /*method*/, bool /*isRaid*/, bool /*isLegacy*/, Player* /*SendMsgTo*/)
+void Group::ResetInstances(InstanceResetMethod method, Player* notifyPlayer)
{
+ for (GroupInstanceReference& ref : m_ownedInstancesMgr)
+ {
+ InstanceMap* map = ref.GetSource();
+ switch (map->Reset(method))
+ {
+ case InstanceResetResult::Success:
+ notifyPlayer->SendResetInstanceSuccess(map->GetId());
+ m_recentInstances.erase(map->GetId());
+ break;
+ case InstanceResetResult::NotEmpty:
+ if (method == InstanceResetMethod::Manual)
+ notifyPlayer->SendResetInstanceFailed(INSTANCE_RESET_FAILED, map->GetId());
+ else if (method == InstanceResetMethod::OnChangeDifficulty)
+ m_recentInstances.erase(map->GetId()); // map might not have been reset on difficulty change but we still don't want to zone in there again
+ break;
+ case InstanceResetResult::CannotReset:
+ m_recentInstances.erase(map->GetId()); // forget the instance, allows retrying different lockout with a new leader
+ break;
+ default:
+ break;
+ }
+ }
}
void Group::LinkOwnedInstance(GroupInstanceReference* ref)
diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h
index 58b27fb459b..3b565aa9c6c 100644
--- a/src/server/game/Groups/Group.h
+++ b/src/server/game/Groups/Group.h
@@ -41,6 +41,8 @@ class WorldSession;
struct ItemDisenchantLootEntry;
struct MapEntry;
+enum class InstanceResetMethod : uint8;
+enum class InstanceResetResult : uint8;
enum LootMethod : uint8;
#define MAX_GROUP_SIZE 5
@@ -304,7 +306,7 @@ class TC_GAME_API Group
Difficulty GetDungeonDifficultyID() const { return m_dungeonDifficulty; }
Difficulty GetRaidDifficultyID() const { return m_raidDifficulty; }
Difficulty GetLegacyRaidDifficultyID() const { return m_legacyRaidDifficulty; }
- void ResetInstances(InstanceResetMethod method, bool isRaid, bool isLegacy, Player* SendMsgTo);
+ void ResetInstances(InstanceResetMethod method, Player* notifyPlayer);
// -no description-
//void SendInit(WorldSession* session);
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 1bcf20acb93..60cdd99619c 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -595,7 +595,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::AreaTrigger::AreaTrigge
reviveAtTrigger = true;
break;
case Map::CANNOT_ENTER_CORPSE_IN_DIFFERENT_INSTANCE:
- player->GetSession()->SendPacket(WorldPackets::AreaTrigger::AreaTriggerNoCorpse().Write());
+ SendPacket(WorldPackets::AreaTrigger::AreaTriggerNoCorpse().Write());
TC_LOG_DEBUG("maps", "MAP: Player '%s' does not have a corpse in instance map %d and cannot enter", player->GetName().c_str(), at->target_mapId);
break;
case Map::CANNOT_ENTER_INSTANCE_BIND_MISMATCH:
@@ -621,6 +621,11 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::AreaTrigger::AreaTrigge
player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_ZONE_IN_COMBAT);
reviveAtTrigger = true;
break;
+ case Map::CANNOT_ENTER_INSTANCE_SHUTTING_DOWN:
+ player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_NOT_FOUND);
+ TC_LOG_DEBUG("maps", "MAP: Player '%s' cannot enter instance map %d because instance is resetting.", player->GetName().c_str(), at->target_mapId);
+ reviveAtTrigger = true;
+ break;
default:
break;
}
@@ -880,13 +885,22 @@ void WorldSession::HandleSetTitleOpcode(WorldPackets::Character::SetTitle& packe
void WorldSession::HandleResetInstancesOpcode(WorldPackets::Instance::ResetInstances& /*packet*/)
{
+ Map* map = _player->FindMap();
+ if (map && map->Instanceable())
+ return;
+
if (Group* group = _player->GetGroup())
{
- if (group->IsLeader(_player->GetGUID()))
- group->ResetInstances(INSTANCE_RESET_ALL, false, false, _player);
+ if (!group->IsLeader(_player->GetGUID()))
+ return;
+
+ if (group->isLFGGroup())
+ return;
+
+ group->ResetInstances(InstanceResetMethod::Manual, _player);
}
else
- _player->ResetInstances(INSTANCE_RESET_ALL, false, false);
+ _player->ResetInstances(InstanceResetMethod::Manual);
}
void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPackets::Misc::SetDungeonDifficulty& setDungeonDifficulty)
@@ -919,7 +933,7 @@ void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPackets::Misc::SetDunge
// cannot reset while in an instance
Map* map = _player->FindMap();
- if (map && map->IsDungeon())
+ if (map && map->Instanceable())
{
TC_LOG_DEBUG("network", "WorldSession::HandleSetDungeonDifficultyOpcode: player (Name: %s, %s) tried to reset the instance while player is inside!",
_player->GetName().c_str(), _player->GetGUID().ToString().c_str());
@@ -929,33 +943,19 @@ void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPackets::Misc::SetDunge
Group* group = _player->GetGroup();
if (group)
{
- if (group->IsLeader(_player->GetGUID()))
- {
- for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
- {
- Player* groupGuy = itr->GetSource();
- if (!groupGuy)
- continue;
+ if (!group->IsLeader(_player->GetGUID()))
+ return;
- if (!groupGuy->IsInWorld())
- return;
+ if (group->isLFGGroup())
+ return;
- if (groupGuy->GetMap()->IsNonRaidDungeon())
- {
- TC_LOG_DEBUG("network", "WorldSession::HandleSetDungeonDifficultyOpcode: player %s tried to reset the instance while group member (Name: %s, %s) is inside!",
- _player->GetGUID().ToString().c_str(), groupGuy->GetName().c_str(), groupGuy->GetGUID().ToString().c_str());
- return;
- }
- }
- // the difficulty is set even if the instances can't be reset
- //_player->SendDungeonDifficulty(true);
- group->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, false, _player);
- group->SetDungeonDifficultyID(difficultyID);
- }
+ // the difficulty is set even if the instances can't be reset
+ group->ResetInstances(InstanceResetMethod::OnChangeDifficulty, _player);
+ group->SetDungeonDifficultyID(difficultyID);
}
else
{
- _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, false);
+ _player->ResetInstances(InstanceResetMethod::OnChangeDifficulty);
_player->SetDungeonDifficultyID(difficultyID);
_player->SendDungeonDifficulty();
}
@@ -985,7 +985,7 @@ void WorldSession::HandleSetRaidDifficultyOpcode(WorldPackets::Misc::SetRaidDiff
return;
}
- if (((difficultyEntry->Flags & DIFFICULTY_FLAG_LEGACY) >> 5) != setRaidDifficulty.Legacy)
+ if (((difficultyEntry->Flags & DIFFICULTY_FLAG_LEGACY) != 0) != setRaidDifficulty.Legacy)
{
TC_LOG_DEBUG("network", "WorldSession::HandleSetDungeonDifficultyOpcode: %s sent not matching legacy difficulty %u!",
_player->GetGUID().ToString().c_str(), difficultyEntry->ID);
@@ -998,7 +998,7 @@ void WorldSession::HandleSetRaidDifficultyOpcode(WorldPackets::Misc::SetRaidDiff
// cannot reset while in an instance
Map* map = _player->FindMap();
- if (map && map->IsDungeon())
+ if (map && map->Instanceable())
{
TC_LOG_DEBUG("network", "WorldSession::HandleSetRaidDifficultyOpcode: player (Name: %s, %s) tried to reset the instance while player is inside!",
_player->GetName().c_str(), _player->GetGUID().ToString().c_str());
@@ -1008,35 +1008,22 @@ void WorldSession::HandleSetRaidDifficultyOpcode(WorldPackets::Misc::SetRaidDiff
Group* group = _player->GetGroup();
if (group)
{
- if (group->IsLeader(_player->GetGUID()))
- {
- for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
- {
- Player* groupGuy = itr->GetSource();
- if (!groupGuy)
- continue;
+ if (!group->IsLeader(_player->GetGUID()))
+ return;
- if (!groupGuy->IsInWorld())
- return;
+ if (group->isLFGGroup())
+ return;
- if (groupGuy->GetMap()->IsRaid())
- {
- TC_LOG_DEBUG("network", "WorldSession::HandleSetRaidDifficultyOpcode: player %s tried to reset the instance while group member (Name: %s, %s) is inside!",
- _player->GetGUID().ToString().c_str(), groupGuy->GetName().c_str(), groupGuy->GetGUID().ToString().c_str());
- return;
- }
- }
- // the difficulty is set even if the instances can't be reset
- group->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, setRaidDifficulty.Legacy != 0, _player);
- if (setRaidDifficulty.Legacy)
- group->SetLegacyRaidDifficultyID(difficultyID);
- else
- group->SetRaidDifficultyID(difficultyID);
- }
+ // the difficulty is set even if the instances can't be reset
+ group->ResetInstances(InstanceResetMethod::OnChangeDifficulty, _player);
+ if (setRaidDifficulty.Legacy)
+ group->SetLegacyRaidDifficultyID(difficultyID);
+ else
+ group->SetRaidDifficultyID(difficultyID);
}
else
{
- _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, setRaidDifficulty.Legacy != 0);
+ _player->ResetInstances(InstanceResetMethod::OnChangeDifficulty);
if (setRaidDifficulty.Legacy)
_player->SetLegacyRaidDifficultyID(difficultyID);
else
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index c8540ac80e7..d2295ac58c9 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -2769,7 +2769,7 @@ template TC_GAME_API void Map::RemoveFromMap(Conversation*, bool);
InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode, TeamId InstanceTeam, InstanceLock* instanceLock)
: Map(id, expiry, InstanceId, SpawnMode),
- m_resetAfterUnload(false), m_unloadWhenEmpty(false),
+ m_shuttingDown(false),
i_data(nullptr), i_script_id(0), i_scenario(nullptr), i_instanceLock(instanceLock)
{
//lets initialize visibility distance for dungeons
@@ -2808,6 +2808,9 @@ Map::EnterState InstanceMap::CannotEnter(Player* player)
return CANNOT_ENTER_ALREADY_IN_MAP;
}
+ if (m_shuttingDown)
+ return CANNOT_ENTER_INSTANCE_SHUTTING_DOWN;
+
// allow GM's to enter
if (player->IsGameMaster())
return Map::CannotEnter(player);
@@ -2867,15 +2870,9 @@ bool InstanceMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
}
}
- // 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;
// this will acquire the same mutex so it cannot be in the previous block
Map::AddPlayerToMap(player, initPlayer);
@@ -2912,15 +2909,12 @@ void InstanceMap::RemovePlayerFromMap(Player* player, bool remove)
// if last player set unload timer
if (!m_unloadTimer && m_mapRefManager.getSize() == 1)
- m_unloadTimer = m_unloadWhenEmpty ? MIN_UNLOAD_DELAY : std::max(sWorld->getIntConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY);
+ m_unloadTimer = m_shuttingDown ? MIN_UNLOAD_DELAY : std::max(sWorld->getIntConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY);
if (i_scenario)
i_scenario->OnPlayerExit(player);
Map::RemovePlayerFromMap(player, remove);
-
- // for normal instances schedule the reset after all players have left
- SetResetSchedule(true);
}
void InstanceMap::CreateInstanceData()
@@ -2966,47 +2960,45 @@ void InstanceMap::TrySetOwningGroup(Group* group)
/*
Returns true if there are no players in the instance
*/
-bool InstanceMap::Reset(InstanceResetMethod method)
+InstanceResetResult InstanceMap::Reset(InstanceResetMethod method)
{
- // note: since the map may not be loaded when the instance needs to be reset
- // the instance must be deleted from the DB
+ // raids can be reset if no boss was killed
+ if (method != InstanceResetMethod::Expire && i_instanceLock && i_instanceLock->GetData()->CompletedEncountersMask)
+ return InstanceResetResult::CannotReset;
if (HavePlayers())
{
- // on manual reset, fail
- if (method == INSTANCE_RESET_ALL || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
- {
- // notify the players to leave the instance so it can be reset
- for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
- itr->GetSource()->SendResetFailedNotify(GetId());
- }
- else
+ switch (method)
{
- // on lock expiration boot players (do we also care about extension state?)
- if (method == INSTANCE_RESET_GLOBAL)
- {
+ case InstanceResetMethod::Manual:
+ // notify the players to leave the instance so it can be reset
+ for (MapReference& ref : m_mapRefManager)
+ ref.GetSource()->SendResetFailedNotify(GetId());
+ break;
+ case InstanceResetMethod::OnChangeDifficulty:
+ // no client notification
+ break;
+ case InstanceResetMethod::Expire:
+ // on lock expiration boot players (do we also care about extension state?)
// set the homebind timer for players inside (1 minute)
- for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
- itr->GetSource()->m_InstanceValid = false;
- }
+ for (MapReference& ref : m_mapRefManager)
+ ref.GetSource()->m_InstanceValid = false;
- if (!HasPermBoundPlayers())
- {
- // the unload timer is not started
- // instead the map will unload immediately after the players have left
- m_unloadWhenEmpty = true;
- m_resetAfterUnload = true;
- }
+ m_shuttingDown = true;
+ break;
+ default:
+ break;
}
+
+ return InstanceResetResult::NotEmpty;
}
else
{
// unloaded at next update
m_unloadTimer = MIN_UNLOAD_DELAY;
- m_resetAfterUnload = !(method == INSTANCE_RESET_GLOBAL && HasPermBoundPlayers());
}
- return m_mapRefManager.isEmpty();
+ return InstanceResetResult::Success;
}
std::string const& InstanceMap::GetScriptName() const
@@ -3128,23 +3120,6 @@ void InstanceMap::CreateInstanceLockForPlayer(Player* player)
}
}
-void InstanceMap::UnloadAll()
-{
- ASSERT(!HavePlayers());
-
- if (m_resetAfterUnload)
- {
- DeleteRespawnTimes();
- DeleteCorpseData();
- }
-
- Map::UnloadAll();
-}
-
-void InstanceMap::SetResetSchedule(bool /*on*/)
-{
-}
-
MapDifficultyEntry const* Map::GetMapDifficulty() const
{
return sDB2Manager.GetMapDifficultyData(GetId(), GetDifficultyID());
@@ -3231,13 +3206,6 @@ bool Map::GetEntrancePos(int32 &mapid, float &x, float &y)
return i_mapEntry->GetEntrancePos(mapid, x, y);
}
-bool InstanceMap::HasPermBoundPlayers() const
-{
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PERM_BIND_BY_INSTANCE);
- stmt->setUInt16(0,GetInstanceId());
- return !!CharacterDatabase.Query(stmt);
-}
-
uint32 InstanceMap::GetMaxPlayers() const
{
MapDifficultyEntry const* mapDiff = GetMapDifficulty();
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 8f06fd77538..732fe9210d9 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -276,6 +276,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
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_INSTANCE_SHUTTING_DOWN,
CANNOT_ENTER_UNSPECIFIED_REASON
};
static EnterState PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck = false);
@@ -787,14 +788,18 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
WorldStateValueContainer _worldStateValues;
};
-enum InstanceResetMethod
+enum class InstanceResetMethod : uint8
{
- INSTANCE_RESET_ALL,
- INSTANCE_RESET_CHANGE_DIFFICULTY,
- INSTANCE_RESET_GLOBAL,
- INSTANCE_RESET_GROUP_DISBAND,
- INSTANCE_RESET_GROUP_JOIN,
- INSTANCE_RESET_RESPAWN_DELAY
+ Manual,
+ OnChangeDifficulty,
+ Expire
+};
+
+enum class InstanceResetResult : uint8
+{
+ Success,
+ NotEmpty,
+ CannotReset
};
class TC_GAME_API InstanceMap : public Map
@@ -806,7 +811,7 @@ class TC_GAME_API InstanceMap : public Map
void RemovePlayerFromMap(Player*, bool) override;
void Update(uint32) override;
void CreateInstanceData();
- bool Reset(InstanceResetMethod method);
+ InstanceResetResult Reset(InstanceResetMethod method);
uint32 GetScriptId() const { return i_script_id; }
std::string const& GetScriptName() const;
InstanceScript* GetInstanceScript() { return i_data; }
@@ -818,13 +823,8 @@ class TC_GAME_API InstanceMap : public Map
void UpdateInstanceLock(UpdateBossStateSaveDataEvent const& updateSaveDataEvent);
void UpdateInstanceLock(UpdateAdditionalSaveDataEvent const& updateSaveDataEvent);
void CreateInstanceLockForPlayer(Player* player);
- void UnloadAll() override;
EnterState CannotEnter(Player* player) override;
- void SetResetSchedule(bool on);
- /* this checks if any players have a permanent bind (included reactivatable expired binds) to the instance ID
- it needs a DB query, so use sparingly */
- bool HasPermBoundPlayers() const;
uint32 GetMaxPlayers() const;
TeamId GetTeamIdInInstance() const;
Team GetTeamInInstance() const { return GetTeamIdInInstance() == TEAM_ALLIANCE ? ALLIANCE : HORDE; }
@@ -836,8 +836,7 @@ class TC_GAME_API InstanceMap : public Map
std::string GetDebugInfo() const override;
private:
- bool m_resetAfterUnload;
- bool m_unloadWhenEmpty;
+ bool m_shuttingDown;
InstanceScript* i_data;
uint32 i_script_id;
InstanceScenario* i_scenario;
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index 788d27301a4..5254559785e 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -335,8 +335,8 @@ bool MapManager::DestroyMap(Map* map)
map->UnloadAll();
- // Free up the instance id and allow it to be reused for bgs and arenas (other instances are handled in the InstanceSaveMgr)
- if (map->IsBattlegroundOrArena())
+ // Free up the instance id and allow it to be reused for normal dungeons, bgs and arenas
+ if (map->IsBattlegroundOrArena() || (map->IsDungeon() && !map->GetMapDifficulty()->HasResetSchedule()))
sMapMgr->FreeInstanceId(map->GetInstanceId());
// erase map