[10114] Store associated InstanceSave for dungeon map in Map object

This commit is contained in:
VladimirMangos 2010-06-27 21:01:29 +04:00
parent 6f4481a591
commit 67a7892075
9 changed files with 89 additions and 62 deletions

View file

@ -1736,8 +1736,8 @@ void Group::_homebindIfInstance(Player *player)
{
// leaving the group in an instance, the homebind timer is started
// unless the player is permanently saved to the instance
InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(player->GetInstanceId());
InstancePlayerBind *playerBind = save ? player->GetBoundInstance(save->GetMapId(), save->GetDifficulty()) : NULL;
Map* map = player->GetMap();
InstancePlayerBind *playerBind = map->IsDungeon() ? player->GetBoundInstance(map->GetId(), map->GetDifficulty()) : NULL;
if(!playerBind || !playerBind->perm)
player->m_InstanceValid = false;
}

View file

@ -43,7 +43,7 @@ INSTANTIATE_SINGLETON_1( InstanceSaveManager );
InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset)
: m_resetTime(resetTime), m_instanceid(InstanceId), m_mapid(MapId),
m_difficulty(difficulty), m_canReset(canReset)
m_difficulty(difficulty), m_canReset(canReset), m_usedByMap(false)
{
}
@ -113,7 +113,7 @@ void InstanceSave::DeleteFromDB()
/* true if the instance save is still valid */
bool InstanceSave::UnloadIfEmpty()
{
if(m_playerList.empty() && m_groupList.empty())
if (m_playerList.empty() && m_groupList.empty() && !m_usedByMap)
{
sInstanceSaveMgr.RemoveInstanceSave(GetInstanceId());
return false;

View file

@ -95,9 +95,17 @@ class InstanceSave
but that would depend on a lot of things that can easily change in future */
Difficulty GetDifficulty() { return m_difficulty; }
void SetUsedByMapState(bool state)
{
m_usedByMap = state;
if (!state)
UnloadIfEmpty();
}
private:
typedef std::list<Player*> PlayerListType;
typedef std::list<Group*> GroupListType;
private:
bool UnloadIfEmpty();
/* the only reason the instSave-object links are kept is because
the object-instSave links need to be broken at reset time
@ -109,6 +117,7 @@ class InstanceSave
uint32 m_mapid;
Difficulty m_difficulty;
bool m_canReset;
bool m_usedByMap; // true when instance map loaded
};
/* resetTime is a global propery of each (raid/heroic) map
@ -170,9 +179,6 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav
InstanceSaveManager();
~InstanceSaveManager();
typedef UNORDERED_MAP<uint32 /*InstanceId*/, InstanceSave*> InstanceSaveHashMap;
typedef UNORDERED_MAP<uint32 /*mapId*/, InstanceSaveHashMap> InstanceSaveMapMap;
void CleanupInstances();
void PackInstances();
@ -182,8 +188,6 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav
void RemoveInstanceSave(uint32 InstanceId);
static void DeleteInstanceFromDB(uint32 instanceid);
InstanceSave *GetInstanceSave(uint32 InstanceId);
/* statistics */
uint32 GetNumInstanceSaves() { return m_instanceSaveById.size(); }
uint32 GetNumBoundPlayersTotal();
@ -191,6 +195,11 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav
void Update() { m_Scheduler.Update(); }
private:
typedef UNORDERED_MAP<uint32 /*InstanceId*/, InstanceSave*> InstanceSaveHashMap;
typedef UNORDERED_MAP<uint32 /*mapId*/, InstanceSaveHashMap> InstanceSaveMapMap;
InstanceSave *GetInstanceSave(uint32 InstanceId);
// called by scheduler
void _ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeleft);
void _ResetInstance(uint32 mapid, uint32 instanceId);

View file

@ -552,7 +552,7 @@ bool ChatHandler::HandleGonameCommand(const char* args)
InstanceGroupBind *gBind = group ? group->GetBoundInstance(target) : NULL;
// if no bind exists, create a solo bind
if (!gBind)
if (InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(target->GetInstanceId()))
if (InstanceSave *save = target->GetMap()->GetInstanceSave())
_player->BindToInstance(save, !save->CanReset());
}

View file

@ -54,6 +54,9 @@ 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
}
void Map::LoadVMap(int gx,int gy)
@ -126,7 +129,7 @@ void Map::LoadMapAndVMap(int gx,int gy)
Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent)
: i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode),
i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0),
m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE),
m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), m_instanceSave(NULL),
m_activeNonPlayersIter(m_activeNonPlayers.end()),
i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this)
{
@ -1723,6 +1726,13 @@ InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 Spaw
// 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);
// Dungeon only code
if(IsDungeon())
{
m_instanceSave = sInstanceSaveMgr.AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true);
m_instanceSave->SetUsedByMapState(true);
}
}
InstanceMap::~InstanceMap()
@ -1783,58 +1793,73 @@ bool InstanceMap::Add(Player *player)
{
Guard guard(*this);
if(!CanEnter(player))
if (!CanEnter(player))
return false;
// Dungeon only code
if(IsDungeon())
if (IsDungeon())
{
// get or create an instance save for the map
InstanceSave *mapSave = sInstanceSaveMgr.GetInstanceSave(GetInstanceId());
if(!mapSave)
{
DETAIL_LOG("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId());
mapSave = sInstanceSaveMgr.AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true);
}
// check for existing instance binds
InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), Difficulty(GetSpawnMode()));
if(playerBind && playerBind->perm)
if (playerBind && playerBind->perm)
{
// cannot enter other instances if bound permanently
if(playerBind->save != mapSave)
if (playerBind->save != GetInstanceSave())
{
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(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset());
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());
ASSERT(false);
}
}
else
{
Group *pGroup = player->GetGroup();
if(pGroup)
if (pGroup)
{
// solo saves should be reset when entering a group
InstanceGroupBind *groupBind = pGroup->GetBoundInstance(this,GetDifficulty());
if(playerBind)
if (playerBind)
{
sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), 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 is bound to instance %d,%d,%d,%d,%d,%d", groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!",
player->GetName(), player->GetGUIDLow(), GetInstanceSave()->GetMapId(), GetInstanceSave()->GetInstanceId(),
GetInstanceSave()->GetDifficulty(), GetInstanceSave()->GetPlayerCount(), GetInstanceSave()->GetGroupCount(),
GetInstanceSave()->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()),
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 is bound to instance %d,%d,%d,%d,%d,%d",
groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(),
groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
ASSERT(false);
}
// bind to the group or keep using the group save
if(!groupBind)
pGroup->BindToInstance(mapSave, false);
if (!groupBind)
pGroup->BindToInstance(GetInstanceSave(), false);
else
{
// cannot jump to a different instance without resetting it
if(groupBind->save != mapSave)
if (groupBind->save != GetInstanceSave())
{
sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d but he is in group %d which is bound to instance %d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), GUID_LOPART(pGroup->GetLeaderGUID()), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty());
if(mapSave)
sLog.outError("MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount());
sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d but he is in group %d which is bound to instance %d,%d,%d!",
player->GetName(), player->GetGUIDLow(), GetInstanceSave()->GetMapId(),
GetInstanceSave()->GetInstanceId(), GetInstanceSave()->GetDifficulty(),
GUID_LOPART(pGroup->GetLeaderGUID()), groupBind->save->GetMapId(),
groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty());
if (GetInstanceSave())
sLog.outError("MapSave players: %d, group count: %d",
GetInstanceSave()->GetPlayerCount(), GetInstanceSave()->GetGroupCount());
else
sLog.outError("MapSave NULL");
if(groupBind->save)
if (groupBind->save)
sLog.outError("GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
else
sLog.outError("GroupBind save NULL");
@ -1842,12 +1867,12 @@ bool InstanceMap::Add(Player *player)
}
// if the group/leader is permanently bound to the instance
// players also become permanently bound when they enter
if(groupBind->perm)
if (groupBind->perm)
{
WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
data << uint32(0);
player->GetSession()->SendPacket(&data);
player->BindToInstance(mapSave, true);
player->BindToInstance(GetInstanceSave(), true);
}
}
}
@ -1855,10 +1880,10 @@ bool InstanceMap::Add(Player *player)
{
// set up a solo bind or continue using it
if(!playerBind)
player->BindToInstance(mapSave, false);
player->BindToInstance(GetInstanceSave(), false);
else
// cannot jump to a different instance without resetting it
ASSERT(playerBind->save == mapSave);
ASSERT(playerBind->save == GetInstanceSave());
}
}
}
@ -1993,13 +2018,6 @@ void InstanceMap::PermBindAllPlayers(Player *player)
if(!IsDungeon())
return;
InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(GetInstanceId());
if(!save)
{
sLog.outError("Cannot bind players, no instance save available for map!");
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)
@ -2007,10 +2025,10 @@ void InstanceMap::PermBindAllPlayers(Player *player)
Player* plr = itr->getSource();
// players inside an instance cannot be bound to other instances
// some players may already be permanently bound, in this case nothing happens
InstancePlayerBind *bind = plr->GetBoundInstance(save->GetMapId(), save->GetDifficulty());
InstancePlayerBind *bind = plr->GetBoundInstance(GetId(), GetDifficulty());
if(!bind || !bind->perm)
{
plr->BindToInstance(save, true);
plr->BindToInstance(GetInstanceSave(), true);
WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
data << uint32(0);
plr->GetSession()->SendPacket(&data);
@ -2018,7 +2036,7 @@ 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->GetGUID())
group->BindToInstance(save, true);
group->BindToInstance(GetInstanceSave(), true);
}
}
@ -2052,13 +2070,7 @@ void InstanceMap::SetResetSchedule(bool on)
// 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())
{
InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(GetInstanceId());
if (!save)
sLog.outError("InstanceMap::SetResetSchedule: cannot turn schedule %s, no save available for instance %d of %d", on ? "on" : "off", GetInstanceId(), GetId());
else
sInstanceSaveMgr.GetScheduler().ScheduleReset(on, save->GetResetTime(), InstanceResetEvent(0, GetId(), Difficulty(GetSpawnMode()), GetInstanceId()));
}
sInstanceSaveMgr.GetScheduler().ScheduleReset(on, GetInstanceSave()->GetResetTime(), InstanceResetEvent(0, GetId(), Difficulty(GetSpawnMode()), GetInstanceId()));
}
/* ******* Battleground Instance Maps ******* */

View file

@ -210,6 +210,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); }
bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); }
InstanceSave* GetInstanceSave() const { return m_instanceSave; }
void AddObjectToRemoveList(WorldObject *obj);
void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair);
@ -312,6 +314,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
uint32 i_InstanceId;
uint32 m_unloadTimer;
float m_VisibleDistance;
InstanceSave* m_instanceSave; // can be NULL for non dungeons...
MapRefManager m_mapRefManager;
MapRefManager::iterator m_mapRefIter;

View file

@ -15213,12 +15213,14 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
}
}
// NOW player must have valid map
// player bounded instance saves loaded in _LoadBoundInstances, group versions at group loading
InstanceSave* instanceSave = GetBoundInstanceSaveForSelfOrGroup(GetMapId());
// load the player's map here if it's not already loaded
SetMap(sMapMgr.CreateMap(GetMapId(), this));
// if the player is in an instance and it has been reset in the meantime teleport him to the entrance
if(GetInstanceId() && !sInstanceSaveMgr.GetInstanceSave(GetInstanceId()))
if(GetInstanceId() && !instanceSave)
{
AreaTrigger const* at = sObjectMgr.GetMapEntranceTrigger(GetMapId());
if(at)

View file

@ -841,8 +841,9 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
// the reset time is set but not added to the scheduler
// until the players leave the instance
time_t resettime = cVictim->GetRespawnTimeEx() + 2 * HOUR;
if(InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(cVictim->GetInstanceId()))
if(save->GetResetTime() < resettime) save->SetResetTime(resettime);
if (InstanceSave *save = m->GetInstanceSave())
if (save->GetResetTime() < resettime)
save->SetResetTime(resettime);
}
}
}

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "10113"
#define REVISION_NR "10114"
#endif // __REVISION_NR_H__