mirror of
https://github.com/mangosfour/server.git
synced 2025-12-14 07:37:01 +00:00
[11126] Rewrite InstanceSaveMgr related code.
* For better fit name to related map type class InstanceMap renamed -> DungeonMap. This clarify usage Instanceable()/IsDungeon() because BG/Arenas maps also instanceable maps. * InstanceSave have many code related to only DungeonMap case, so it replaced by 3 new classes: - MapPersistentState as base class, used for non-instanceable maps (continents and some other) (!Instenceable()) - DungeonPersistentState subclass of MapPersistentState, used for DungeonMap states (IsDungoen()) - BattlegroundPersistentState subclass of MapPersistentState, used for BattlegroundMap states (IsBattleGroundOrArena()) Now all dungeon resets code moved to subclass and all player/gpoup bound functions/structures also use it. * Map::GetInstanceSave renamed to Map::GetPersistentState and DungeonMap have specialized version return DungeonPersistentState (same pointer in fact with proper subcalss type) * InstanceResetScheduler renamed to DungeonResetScheduler
This commit is contained in:
parent
0d16b0bdc7
commit
dde16bc48c
22 changed files with 683 additions and 550 deletions
243
src/game/Map.cpp
243
src/game/Map.cpp
|
|
@ -46,8 +46,8 @@ Map::~Map()
|
|||
if(!m_scriptSchedule.empty())
|
||||
sWorld.DecreaseScheduledScriptCount(m_scriptSchedule.size());
|
||||
|
||||
if (m_instanceSave)
|
||||
m_instanceSave->SetUsedByMapState(false); // field pointer can be deleted after this
|
||||
if (m_persistentState)
|
||||
m_persistentState->SetUsedByMapState(false); // field pointer can be deleted after this
|
||||
|
||||
if(i_data)
|
||||
{
|
||||
|
|
@ -73,7 +73,7 @@ void Map::LoadMapAndVMap(int gx,int gy)
|
|||
Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
|
||||
: i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode),
|
||||
i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0),
|
||||
m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), m_instanceSave(NULL),
|
||||
m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), m_persistentState(NULL),
|
||||
m_activeNonPlayersIter(m_activeNonPlayers.end()),
|
||||
i_gridExpiry(expiry), m_TerrainData(sTerrainMgr.LoadTerrain(id)),
|
||||
i_data(NULL), i_script_id(0)
|
||||
|
|
@ -95,8 +95,8 @@ Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
|
|||
//add reference for TerrainData object
|
||||
m_TerrainData->AddRef();
|
||||
|
||||
m_instanceSave = sInstanceSaveMgr.AddInstanceSave(i_mapEntry, GetInstanceId(), GetDifficulty(), 0, IsDungeon());
|
||||
m_instanceSave->SetUsedByMapState(true);
|
||||
m_persistentState = sMapPersistentStateMgr.AddPersistentState(i_mapEntry, GetInstanceId(), GetDifficulty(), 0, IsDungeon());
|
||||
m_persistentState->SetUsedByMapState(true);
|
||||
}
|
||||
|
||||
void Map::InitVisibilityDistance()
|
||||
|
|
@ -928,7 +928,7 @@ uint32 Map::GetMaxPlayers() const
|
|||
|
||||
uint32 Map::GetMaxResetDelay() const
|
||||
{
|
||||
return InstanceResetScheduler::GetMaxResetTimeFor(GetMapDifficulty());
|
||||
return DungeonResetScheduler::GetMaxResetTimeFor(GetMapDifficulty());
|
||||
}
|
||||
|
||||
bool Map::CheckGridIntegrity(Creature* c, bool moved) const
|
||||
|
|
@ -1304,23 +1304,25 @@ template void Map::Remove(DynamicObject *, bool);
|
|||
|
||||
/* ******* Dungeon Instance Maps ******* */
|
||||
|
||||
InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
|
||||
DungeonMap::DungeonMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
|
||||
: Map(id, expiry, InstanceId, SpawnMode),
|
||||
m_resetAfterUnload(false), m_unloadWhenEmpty(false)
|
||||
{
|
||||
MANGOS_ASSERT(i_mapEntry->IsDungeon());
|
||||
|
||||
//lets initialize visibility distance for dungeons
|
||||
InstanceMap::InitVisibilityDistance();
|
||||
DungeonMap::InitVisibilityDistance();
|
||||
|
||||
// the timer is started by default, and stopped when the first player joins
|
||||
// this make sure it gets unloaded if for some reason no player joins
|
||||
m_unloadTimer = std::max(sWorld.getConfig(CONFIG_UINT32_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY);
|
||||
}
|
||||
|
||||
InstanceMap::~InstanceMap()
|
||||
DungeonMap::~DungeonMap()
|
||||
{
|
||||
}
|
||||
|
||||
void InstanceMap::InitVisibilityDistance()
|
||||
void DungeonMap::InitVisibilityDistance()
|
||||
{
|
||||
//init visibility distance for instances
|
||||
m_VisibleDistance = World::GetMaxVisibleDistanceInInstances();
|
||||
|
|
@ -1329,11 +1331,11 @@ void InstanceMap::InitVisibilityDistance()
|
|||
/*
|
||||
Do map specific checks to see if the player can enter
|
||||
*/
|
||||
bool InstanceMap::CanEnter(Player *player)
|
||||
bool DungeonMap::CanEnter(Player *player)
|
||||
{
|
||||
if(player->GetMapRef().getTarget() == this)
|
||||
{
|
||||
sLog.outError("InstanceMap::CanEnter - player %s(%u) already in map %d,%d,%d!", player->GetName(), player->GetGUIDLow(), GetId(), GetInstanceId(), GetSpawnMode());
|
||||
sLog.outError("DungeonMap::CanEnter - player %s(%u) already in map %d,%d,%d!", player->GetName(), player->GetGUIDLow(), GetId(), GetInstanceId(), GetSpawnMode());
|
||||
MANGOS_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1361,7 +1363,7 @@ bool InstanceMap::CanEnter(Player *player)
|
|||
/*
|
||||
Do map specific checks and add the player to the map if successful.
|
||||
*/
|
||||
bool InstanceMap::Add(Player *player)
|
||||
bool DungeonMap::Add(Player *player)
|
||||
{
|
||||
// TODO: Not sure about checking player level: already done in HandleAreaTriggerOpcode
|
||||
// GMs still can teleport player in instance.
|
||||
|
|
@ -1370,96 +1372,92 @@ bool InstanceMap::Add(Player *player)
|
|||
if (!CanEnter(player))
|
||||
return false;
|
||||
|
||||
// Dungeon only code
|
||||
if (IsDungeon())
|
||||
// check for existing instance binds
|
||||
InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), GetDifficulty());
|
||||
if (playerBind && playerBind->perm)
|
||||
{
|
||||
// check for existing instance binds
|
||||
InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), GetDifficulty());
|
||||
if (playerBind && playerBind->perm)
|
||||
// cannot enter other instances if bound permanently
|
||||
if (playerBind->state != GetPersistanceState())
|
||||
{
|
||||
// cannot enter other instances if bound permanently
|
||||
if (playerBind->save != GetInstanceSave())
|
||||
sLog.outError("DungeonMap::Add: player %s(%d) is permanently bound to instance %d,%d,%d,%d,%d,%d but he is being put in instance %d,%d,%d,%d,%d,%d",
|
||||
player->GetName(), player->GetGUIDLow(), playerBind->state->GetMapId(),
|
||||
playerBind->state->GetInstanceId(), playerBind->state->GetDifficulty(),
|
||||
playerBind->state->GetPlayerCount(), playerBind->state->GetGroupCount(),
|
||||
playerBind->state->CanReset(),
|
||||
GetPersistanceState()->GetMapId(), GetPersistanceState()->GetInstanceId(),
|
||||
GetPersistanceState()->GetDifficulty(), GetPersistanceState()->GetPlayerCount(),
|
||||
GetPersistanceState()->GetGroupCount(), GetPersistanceState()->CanReset());
|
||||
MANGOS_ASSERT(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Group *pGroup = player->GetGroup();
|
||||
if (pGroup)
|
||||
{
|
||||
// solo saves should be reset when entering a group
|
||||
InstanceGroupBind *groupBind = pGroup->GetBoundInstance(this,GetDifficulty());
|
||||
if (playerBind)
|
||||
{
|
||||
sLog.outError("InstanceMap::Add: player %s(%d) is permanently bound to instance %d,%d,%d,%d,%d,%d but he is being put in instance %d,%d,%d,%d,%d,%d",
|
||||
player->GetName(), player->GetGUIDLow(), playerBind->save->GetMapId(),
|
||||
playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(),
|
||||
playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(),
|
||||
playerBind->save->CanReset(),
|
||||
GetInstanceSave()->GetMapId(), GetInstanceSave()->GetInstanceId(),
|
||||
GetInstanceSave()->GetDifficulty(), GetInstanceSave()->GetPlayerCount(),
|
||||
GetInstanceSave()->GetGroupCount(), GetInstanceSave()->CanReset());
|
||||
MANGOS_ASSERT(false);
|
||||
sLog.outError("DungeonMap::Add: %s is being put in instance %d,%d,%d,%d,%d,%d but he is in group (Id: %d) and is bound to instance %d,%d,%d,%d,%d,%d!",
|
||||
player->GetGuidStr().c_str(), GetPersistentState()->GetMapId(), GetPersistentState()->GetInstanceId(),
|
||||
GetPersistanceState()->GetDifficulty(), GetPersistanceState()->GetPlayerCount(), GetPersistanceState()->GetGroupCount(),
|
||||
GetPersistanceState()->CanReset(), pGroup->GetId(),
|
||||
playerBind->state->GetMapId(), playerBind->state->GetInstanceId(), playerBind->state->GetDifficulty(),
|
||||
playerBind->state->GetPlayerCount(), playerBind->state->GetGroupCount(), playerBind->state->CanReset());
|
||||
|
||||
if (groupBind)
|
||||
sLog.outError("DungeonMap::Add: the group (Id: %d) is bound to instance %d,%d,%d,%d,%d,%d",
|
||||
pGroup->GetId(),
|
||||
groupBind->state->GetMapId(), groupBind->state->GetInstanceId(), groupBind->state->GetDifficulty(),
|
||||
groupBind->state->GetPlayerCount(), groupBind->state->GetGroupCount(), groupBind->state->CanReset());
|
||||
|
||||
// no reason crash if we can fix state
|
||||
player->UnbindInstance(GetId(), GetDifficulty());
|
||||
}
|
||||
|
||||
// bind to the group or keep using the group save
|
||||
if (!groupBind)
|
||||
pGroup->BindToInstance(GetPersistanceState(), false);
|
||||
else
|
||||
{
|
||||
// cannot jump to a different instance without resetting it
|
||||
if (groupBind->state != GetPersistentState())
|
||||
{
|
||||
sLog.outError("DungeonMap::Add: %s is being put in instance %d,%d,%d but he is in group (Id: %d) which is bound to instance %d,%d,%d!",
|
||||
player->GetGuidStr().c_str(), GetPersistentState()->GetMapId(),
|
||||
GetPersistentState()->GetInstanceId(), GetPersistentState()->GetDifficulty(),
|
||||
pGroup->GetId(), groupBind->state->GetMapId(),
|
||||
groupBind->state->GetInstanceId(), groupBind->state->GetDifficulty());
|
||||
|
||||
sLog.outError("MapSave players: %d, group count: %d",
|
||||
GetPersistanceState()->GetPlayerCount(), GetPersistanceState()->GetGroupCount());
|
||||
|
||||
if (groupBind->state)
|
||||
sLog.outError("GroupBind save players: %d, group count: %d", groupBind->state->GetPlayerCount(), groupBind->state->GetGroupCount());
|
||||
else
|
||||
sLog.outError("GroupBind save NULL");
|
||||
MANGOS_ASSERT(false);
|
||||
}
|
||||
// if the group/leader is permanently bound to the instance
|
||||
// players also become permanently bound when they enter
|
||||
if (groupBind->perm)
|
||||
{
|
||||
WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
|
||||
data << uint32(0);
|
||||
player->GetSession()->SendPacket(&data);
|
||||
player->BindToInstance(GetPersistanceState(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Group *pGroup = player->GetGroup();
|
||||
if (pGroup)
|
||||
{
|
||||
// solo saves should be reset when entering a group
|
||||
InstanceGroupBind *groupBind = pGroup->GetBoundInstance(this,GetDifficulty());
|
||||
if (playerBind)
|
||||
{
|
||||
sLog.outError("InstanceMap::Add: %s is being put in instance %d,%d,%d,%d,%d,%d but he is in group (Id: %d) and is bound to instance %d,%d,%d,%d,%d,%d!",
|
||||
player->GetGuidStr().c_str(), GetInstanceSave()->GetMapId(), GetInstanceSave()->GetInstanceId(),
|
||||
GetInstanceSave()->GetDifficulty(), GetInstanceSave()->GetPlayerCount(), GetInstanceSave()->GetGroupCount(),
|
||||
GetInstanceSave()->CanReset(), pGroup->GetId(),
|
||||
playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(),
|
||||
playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
|
||||
|
||||
if (groupBind)
|
||||
sLog.outError("InstanceMap::Add: the group (Id: %d) is bound to instance %d,%d,%d,%d,%d,%d",
|
||||
pGroup->GetId(),
|
||||
groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(),
|
||||
groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
|
||||
|
||||
// no reason crash if we can fix state
|
||||
player->UnbindInstance(GetId(), GetDifficulty());
|
||||
}
|
||||
|
||||
// bind to the group or keep using the group save
|
||||
if (!groupBind)
|
||||
pGroup->BindToInstance(GetInstanceSave(), false);
|
||||
else
|
||||
{
|
||||
// cannot jump to a different instance without resetting it
|
||||
if (groupBind->save != GetInstanceSave())
|
||||
{
|
||||
sLog.outError("InstanceMap::Add: %s is being put in instance %d,%d,%d but he is in group (Id: %d) which is bound to instance %d,%d,%d!",
|
||||
player->GetGuidStr().c_str(), GetInstanceSave()->GetMapId(),
|
||||
GetInstanceSave()->GetInstanceId(), GetInstanceSave()->GetDifficulty(),
|
||||
pGroup->GetId(), groupBind->save->GetMapId(),
|
||||
groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty());
|
||||
|
||||
sLog.outError("MapSave players: %d, group count: %d",
|
||||
GetInstanceSave()->GetPlayerCount(), GetInstanceSave()->GetGroupCount());
|
||||
|
||||
if (groupBind->save)
|
||||
sLog.outError("GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
|
||||
else
|
||||
sLog.outError("GroupBind save NULL");
|
||||
MANGOS_ASSERT(false);
|
||||
}
|
||||
// if the group/leader is permanently bound to the instance
|
||||
// players also become permanently bound when they enter
|
||||
if (groupBind->perm)
|
||||
{
|
||||
WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
|
||||
data << uint32(0);
|
||||
player->GetSession()->SendPacket(&data);
|
||||
player->BindToInstance(GetInstanceSave(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// set up a solo bind or continue using it
|
||||
if(!playerBind)
|
||||
player->BindToInstance(GetPersistanceState(), false);
|
||||
else
|
||||
{
|
||||
// set up a solo bind or continue using it
|
||||
if(!playerBind)
|
||||
player->BindToInstance(GetInstanceSave(), false);
|
||||
else
|
||||
// cannot jump to a different instance without resetting it
|
||||
MANGOS_ASSERT(playerBind->save == GetInstanceSave());
|
||||
}
|
||||
// cannot jump to a different instance without resetting it
|
||||
MANGOS_ASSERT(playerBind->state == GetPersistentState());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1479,19 +1477,12 @@ bool InstanceMap::Add(Player *player)
|
|||
return true;
|
||||
}
|
||||
|
||||
void InstanceMap::Update(const uint32& t_diff)
|
||||
void DungeonMap::Update(const uint32& t_diff)
|
||||
{
|
||||
Map::Update(t_diff);
|
||||
}
|
||||
|
||||
void BattleGroundMap::Update(const uint32& diff)
|
||||
{
|
||||
Map::Update(diff);
|
||||
|
||||
GetBG()->Update(diff);
|
||||
}
|
||||
|
||||
void InstanceMap::Remove(Player *player, bool remove)
|
||||
void DungeonMap::Remove(Player *player, bool remove)
|
||||
{
|
||||
DETAIL_LOG("MAP: Removing player '%s' from instance '%u' of map '%s' before relocating to other map", player->GetName(), GetInstanceId(), GetMapName());
|
||||
|
||||
|
|
@ -1508,7 +1499,7 @@ void InstanceMap::Remove(Player *player, bool remove)
|
|||
/*
|
||||
Returns true if there are no players in the instance
|
||||
*/
|
||||
bool InstanceMap::Reset(InstanceResetMethod method)
|
||||
bool DungeonMap::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 by InstanceSaveManager
|
||||
|
|
@ -1546,11 +1537,8 @@ bool InstanceMap::Reset(InstanceResetMethod method)
|
|||
return m_mapRefManager.isEmpty();
|
||||
}
|
||||
|
||||
void InstanceMap::PermBindAllPlayers(Player *player)
|
||||
void DungeonMap::PermBindAllPlayers(Player *player)
|
||||
{
|
||||
if (!IsDungeon())
|
||||
return;
|
||||
|
||||
Group *group = player->GetGroup();
|
||||
// group members outside the instance group don't get bound
|
||||
for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
|
||||
|
|
@ -1561,7 +1549,7 @@ void InstanceMap::PermBindAllPlayers(Player *player)
|
|||
InstancePlayerBind *bind = plr->GetBoundInstance(GetId(), GetDifficulty());
|
||||
if (!bind || !bind->perm)
|
||||
{
|
||||
plr->BindToInstance(GetInstanceSave(), true);
|
||||
plr->BindToInstance(GetPersistanceState(), true);
|
||||
WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
|
||||
data << uint32(0);
|
||||
plr->GetSession()->SendPacket(&data);
|
||||
|
|
@ -1569,15 +1557,15 @@ void InstanceMap::PermBindAllPlayers(Player *player)
|
|||
|
||||
// if the leader is not in the instance the group will not get a perm bind
|
||||
if (group && group->GetLeaderGuid() == plr->GetObjectGuid())
|
||||
group->BindToInstance(GetInstanceSave(), true);
|
||||
group->BindToInstance(GetPersistanceState(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceMap::UnloadAll(bool pForce)
|
||||
void DungeonMap::UnloadAll(bool pForce)
|
||||
{
|
||||
if(HavePlayers())
|
||||
{
|
||||
sLog.outError("InstanceMap::UnloadAll: there are still players in the instance at unload, should not happen!");
|
||||
sLog.outError("DungeonMap::UnloadAll: there are still players in the instance at unload, should not happen!");
|
||||
for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
|
||||
{
|
||||
Player* plr = itr->getSource();
|
||||
|
|
@ -1586,26 +1574,32 @@ void InstanceMap::UnloadAll(bool pForce)
|
|||
}
|
||||
|
||||
if(m_resetAfterUnload == true)
|
||||
GetInstanceSave()->DeleteRespawnTimes();
|
||||
GetPersistanceState()->DeleteRespawnTimes();
|
||||
|
||||
Map::UnloadAll(pForce);
|
||||
}
|
||||
|
||||
void InstanceMap::SendResetWarnings(uint32 timeLeft) const
|
||||
void DungeonMap::SendResetWarnings(uint32 timeLeft) const
|
||||
{
|
||||
for(MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
|
||||
itr->getSource()->SendInstanceResetWarning(GetId(), itr->getSource()->GetDifficulty(IsRaid()), timeLeft);
|
||||
}
|
||||
|
||||
void InstanceMap::SetResetSchedule(bool on)
|
||||
void DungeonMap::SetResetSchedule(bool on)
|
||||
{
|
||||
// only for normal instances
|
||||
// the reset time is only scheduled when there are no payers inside
|
||||
// it is assumed that the reset time will rarely (if ever) change while the reset is scheduled
|
||||
if(IsDungeon() && !HavePlayers() && !IsRaidOrHeroicDungeon())
|
||||
sInstanceSaveMgr.GetScheduler().ScheduleReset(on, GetInstanceSave()->GetResetTime(), InstanceResetEvent(RESET_EVENT_DUNGEON, GetId(), Difficulty(GetSpawnMode()), GetInstanceId()));
|
||||
if(!HavePlayers() && !IsRaidOrHeroicDungeon())
|
||||
sMapPersistentStateMgr.GetScheduler().ScheduleReset(on, GetPersistanceState()->GetResetTime(), DungeonResetEvent(RESET_EVENT_NORMAL_DUNGEON, GetId(), Difficulty(GetSpawnMode()), GetInstanceId()));
|
||||
}
|
||||
|
||||
DungeonPersistentState* DungeonMap::GetPersistanceState() const
|
||||
{
|
||||
return (DungeonPersistentState*)Map::GetPersistentState();
|
||||
}
|
||||
|
||||
|
||||
/* ******* Battleground Instance Maps ******* */
|
||||
|
||||
BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 spawnMode)
|
||||
|
|
@ -1619,6 +1613,19 @@ BattleGroundMap::~BattleGroundMap()
|
|||
{
|
||||
}
|
||||
|
||||
void BattleGroundMap::Update(const uint32& diff)
|
||||
{
|
||||
Map::Update(diff);
|
||||
|
||||
GetBG()->Update(diff);
|
||||
}
|
||||
|
||||
BattleGroundPersistentState* BattleGroundMap::GetPersistanceState() const
|
||||
{
|
||||
return (BattleGroundPersistentState*)Map::GetPersistentState();
|
||||
}
|
||||
|
||||
|
||||
void BattleGroundMap::InitVisibilityDistance()
|
||||
{
|
||||
//init visibility distance for BG/Arenas
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue