mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 10:37:03 +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
|
|
@ -42,7 +42,7 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket &/*recv_data*/)
|
|||
|
||||
uint32 counter = 0;
|
||||
size_t p_counter = data.wpos();
|
||||
data << uint32(counter); // instance save count
|
||||
data << uint32(counter); // instance state count
|
||||
|
||||
for(int i = 0; i < MAX_DIFFICULTY; ++i)
|
||||
{
|
||||
|
|
@ -50,11 +50,11 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket &/*recv_data*/)
|
|||
{
|
||||
if(itr->second.perm)
|
||||
{
|
||||
InstanceSave *save = itr->second.save;
|
||||
data << uint32(save->GetMapId());
|
||||
data << uint32(save->GetDifficulty());
|
||||
data << uint32(save->GetResetTime() - cur_time);
|
||||
data << ObjectGuid(save->GetInstanceGuid());
|
||||
DungeonPersistentState *state = itr->second.state;
|
||||
data << uint32(state->GetMapId());
|
||||
data << uint32(state->GetDifficulty());
|
||||
data << uint32(state->GetResetTime() - cur_time);
|
||||
data << ObjectGuid(state->GetInstanceGuid());
|
||||
++counter;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1270,7 +1270,7 @@ bool Creature::LoadFromDB(uint32 guidlow, Map *map)
|
|||
m_isDeadByDefault = data->is_dead;
|
||||
m_deathState = m_isDeadByDefault ? DEAD : ALIVE;
|
||||
|
||||
m_respawnTime = map->GetInstanceSave()->GetCreatureRespawnTime(m_DBTableGuid);
|
||||
m_respawnTime = map->GetPersistentState()->GetCreatureRespawnTime(m_DBTableGuid);
|
||||
|
||||
if(m_respawnTime > time(NULL)) // not ready to respawn
|
||||
{
|
||||
|
|
@ -1286,7 +1286,7 @@ bool Creature::LoadFromDB(uint32 guidlow, Map *map)
|
|||
{
|
||||
m_respawnTime = 0;
|
||||
|
||||
GetMap()->GetInstanceSave()->SaveCreatureRespawnTime(m_DBTableGuid, 0);
|
||||
GetMap()->GetPersistentState()->SaveCreatureRespawnTime(m_DBTableGuid, 0);
|
||||
}
|
||||
|
||||
uint32 curhealth = data->curhealth;
|
||||
|
|
@ -1362,7 +1362,7 @@ void Creature::DeleteFromDB()
|
|||
}
|
||||
|
||||
// FIXME: this not safe for another map copies can be
|
||||
if (InstanceSave* save = sInstanceSaveMgr.GetInstanceSave(GetMapId(), GetInstanceId()))
|
||||
if (MapPersistentState* save = sMapPersistentStateMgr.GetPersistentState(GetMapId(), GetInstanceId()))
|
||||
save->SaveCreatureRespawnTime(m_DBTableGuid, 0);
|
||||
|
||||
sObjectMgr.DeleteCreatureData(m_DBTableGuid);
|
||||
|
|
@ -1522,7 +1522,7 @@ void Creature::Respawn()
|
|||
if (IsDespawned())
|
||||
{
|
||||
if (m_DBTableGuid)
|
||||
GetMap()->GetInstanceSave()->SaveCreatureRespawnTime(m_DBTableGuid, 0);
|
||||
GetMap()->GetPersistentState()->SaveCreatureRespawnTime(m_DBTableGuid, 0);
|
||||
m_respawnTime = time(NULL); // respawn at next tick
|
||||
}
|
||||
}
|
||||
|
|
@ -1821,9 +1821,9 @@ void Creature::SaveRespawnTime()
|
|||
return;
|
||||
|
||||
if(m_respawnTime > time(NULL)) // dead (no corpse)
|
||||
GetMap()->GetInstanceSave()->SaveCreatureRespawnTime(m_DBTableGuid, m_respawnTime);
|
||||
GetMap()->GetPersistentState()->SaveCreatureRespawnTime(m_DBTableGuid, m_respawnTime);
|
||||
else if (m_corpseDecayTimer > 0) // dead (corpse)
|
||||
GetMap()->GetInstanceSave()->SaveCreatureRespawnTime(m_DBTableGuid, time(NULL) + m_respawnDelay + m_corpseDecayTimer / IN_MILLISECONDS);
|
||||
GetMap()->GetPersistentState()->SaveCreatureRespawnTime(m_DBTableGuid, time(NULL) + m_respawnDelay + m_corpseDecayTimer / IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
bool Creature::IsOutOfThreatArea(Unit* pVictim) const
|
||||
|
|
|
|||
|
|
@ -598,13 +598,13 @@ bool GameObject::LoadFromDB(uint32 guid, Map *map)
|
|||
m_spawnedByDefault = true;
|
||||
m_respawnDelayTime = data->spawntimesecs;
|
||||
|
||||
m_respawnTime = map->GetInstanceSave()->GetGORespawnTime(m_DBTableGuid);
|
||||
m_respawnTime = map->GetPersistentState()->GetGORespawnTime(m_DBTableGuid);
|
||||
|
||||
// ready to respawn
|
||||
if (m_respawnTime && m_respawnTime <= time(NULL))
|
||||
{
|
||||
m_respawnTime = 0;
|
||||
map->GetInstanceSave()->SaveGORespawnTime(m_DBTableGuid, 0);
|
||||
map->GetPersistentState()->SaveGORespawnTime(m_DBTableGuid, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -621,7 +621,7 @@ bool GameObject::LoadFromDB(uint32 guid, Map *map)
|
|||
void GameObject::DeleteFromDB()
|
||||
{
|
||||
// FIXME: this can be not safe in case multiply loaded instance copies
|
||||
if (InstanceSave* save = sInstanceSaveMgr.GetInstanceSave(GetMapId(), GetInstanceId()))
|
||||
if (MapPersistentState* save = sMapPersistentStateMgr.GetPersistentState(GetMapId(), GetInstanceId()))
|
||||
save->SaveGORespawnTime(m_DBTableGuid, 0);
|
||||
|
||||
sObjectMgr.DeleteGOData(m_DBTableGuid);
|
||||
|
|
@ -676,7 +676,7 @@ Unit* GameObject::GetOwner() const
|
|||
void GameObject::SaveRespawnTime()
|
||||
{
|
||||
if(m_respawnTime > time(NULL) && m_spawnedByDefault)
|
||||
GetMap()->GetInstanceSave()->SaveGORespawnTime(m_DBTableGuid, m_respawnTime);
|
||||
GetMap()->GetPersistentState()->SaveGORespawnTime(m_DBTableGuid, m_respawnTime);
|
||||
}
|
||||
|
||||
bool GameObject::isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const
|
||||
|
|
@ -719,7 +719,7 @@ void GameObject::Respawn()
|
|||
if(m_spawnedByDefault && m_respawnTime > 0)
|
||||
{
|
||||
m_respawnTime = time(NULL);
|
||||
GetMap()->GetInstanceSave()->SaveGORespawnTime(m_DBTableGuid, 0);
|
||||
GetMap()->GetPersistentState()->SaveGORespawnTime(m_DBTableGuid, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ class Unit;
|
|||
class WorldPacket;
|
||||
class InstanceData;
|
||||
class Group;
|
||||
class InstanceSave;
|
||||
struct ScriptInfo;
|
||||
struct ScriptAction;
|
||||
class BattleGround;
|
||||
|
|
|
|||
|
|
@ -103,10 +103,10 @@ Group::~Group()
|
|||
|
||||
// it is undefined whether objectmgr (which stores the groups) or instancesavemgr
|
||||
// will be unloaded first so we must be prepared for both cases
|
||||
// this may unload some instance saves
|
||||
// this may unload some dungeon persistent state
|
||||
for(uint8 i = 0; i < MAX_DIFFICULTY; ++i)
|
||||
for(BoundInstancesMap::iterator itr2 = m_boundInstances[i].begin(); itr2 != m_boundInstances[i].end(); ++itr2)
|
||||
itr2->second.save->RemoveGroup(this);
|
||||
itr2->second.state->RemoveGroup(this);
|
||||
|
||||
// Sub group counters clean up
|
||||
if (m_subGroupsCounts)
|
||||
|
|
@ -1170,11 +1170,11 @@ bool Group::_addMember(ObjectGuid guid, const char* name, bool isAssistant, uint
|
|||
|
||||
SubGroupCounterIncrease(group);
|
||||
|
||||
if(player)
|
||||
if (player)
|
||||
{
|
||||
player->SetGroupInvite(NULL);
|
||||
//if player is in group and he is being added to BG raid group, then call SetBattleGroundRaid()
|
||||
if( player->GetGroup() && isBGGroup() )
|
||||
if (player->GetGroup() && isBGGroup())
|
||||
player->SetBattleGroundRaid(this, group);
|
||||
//if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup()
|
||||
else if ( player->GetGroup() )
|
||||
|
|
@ -1182,19 +1182,20 @@ bool Group::_addMember(ObjectGuid guid, const char* name, bool isAssistant, uint
|
|||
//if player is not in group, then call set group
|
||||
else
|
||||
player->SetGroup(this, group);
|
||||
|
||||
// if the same group invites the player back, cancel the homebind timer
|
||||
InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player);
|
||||
if(bind && bind->save->GetInstanceId() == player->GetInstanceId())
|
||||
if (InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player))
|
||||
if (bind->state->GetInstanceId() == player->GetInstanceId())
|
||||
player->m_InstanceValid = true;
|
||||
}
|
||||
|
||||
if(!isRaidGroup()) // reset targetIcons for non-raid-groups
|
||||
if (!isRaidGroup()) // reset targetIcons for non-raid-groups
|
||||
{
|
||||
for(int i = 0; i < TARGET_ICON_COUNT; ++i)
|
||||
m_targetIcons[i].Clear();
|
||||
}
|
||||
|
||||
if(!isBGGroup())
|
||||
if (!isBGGroup())
|
||||
{
|
||||
// insert into group table
|
||||
CharacterDatabase.PExecute("INSERT INTO group_member(groupId,memberGuid,assistant,subgroup) VALUES('%u','%u','%u','%u')",
|
||||
|
|
@ -1280,7 +1281,7 @@ void Group::_setLeader(ObjectGuid guid)
|
|||
{
|
||||
if(itr->second.perm)
|
||||
{
|
||||
itr->second.save->RemoveGroup(this);
|
||||
itr->second.state->RemoveGroup(this);
|
||||
m_boundInstances[i].erase(itr++);
|
||||
}
|
||||
else
|
||||
|
|
@ -1676,9 +1677,9 @@ void Group::ResetInstances(InstanceResetMethod method, bool isRaid, Player* Send
|
|||
|
||||
for(BoundInstancesMap::iterator itr = m_boundInstances[diff].begin(); itr != m_boundInstances[diff].end();)
|
||||
{
|
||||
InstanceSave *p = itr->second.save;
|
||||
DungeonPersistentState *state = itr->second.state;
|
||||
const MapEntry *entry = sMapStore.LookupEntry(itr->first);
|
||||
if (!entry || entry->IsRaid() != isRaid || (!p->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND))
|
||||
if (!entry || entry->IsRaid() != isRaid || (!state->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND))
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
|
|
@ -1696,31 +1697,31 @@ void Group::ResetInstances(InstanceResetMethod method, bool isRaid, Player* Send
|
|||
|
||||
bool isEmpty = true;
|
||||
// if the map is loaded, reset it
|
||||
Map *map = sMapMgr.FindMap(p->GetMapId(), p->GetInstanceId());
|
||||
if(map && map->IsDungeon() && !(method == INSTANCE_RESET_GROUP_DISBAND && !p->CanReset()))
|
||||
isEmpty = ((InstanceMap*)map)->Reset(method);
|
||||
if (Map *map = sMapMgr.FindMap(state->GetMapId(), state->GetInstanceId()))
|
||||
if (map->IsDungeon() && !(method == INSTANCE_RESET_GROUP_DISBAND && !state->CanReset()))
|
||||
isEmpty = ((DungeonMap*)map)->Reset(method);
|
||||
|
||||
if(SendMsgTo)
|
||||
if (SendMsgTo)
|
||||
{
|
||||
if(isEmpty)
|
||||
SendMsgTo->SendResetInstanceSuccess(p->GetMapId());
|
||||
if (isEmpty)
|
||||
SendMsgTo->SendResetInstanceSuccess(state->GetMapId());
|
||||
else
|
||||
SendMsgTo->SendResetInstanceFailed(0, p->GetMapId());
|
||||
SendMsgTo->SendResetInstanceFailed(0, state->GetMapId());
|
||||
}
|
||||
|
||||
if(isEmpty || method == INSTANCE_RESET_GROUP_DISBAND || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
|
||||
if (isEmpty || method == INSTANCE_RESET_GROUP_DISBAND || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
|
||||
{
|
||||
// do not reset the instance, just unbind if others are permanently bound to it
|
||||
if(p->CanReset())
|
||||
p->DeleteFromDB();
|
||||
if (state->CanReset())
|
||||
state->DeleteFromDB();
|
||||
else
|
||||
CharacterDatabase.PExecute("DELETE FROM group_instance WHERE instance = '%u'", p->GetInstanceId());
|
||||
CharacterDatabase.PExecute("DELETE FROM group_instance WHERE instance = '%u'", state->GetInstanceId());
|
||||
// i don't know for sure if hash_map iterators
|
||||
m_boundInstances[diff].erase(itr);
|
||||
itr = m_boundInstances[diff].begin();
|
||||
// this unloads the instance save unless online players are bound to it
|
||||
// (eg. permanent binds or GM solo binds)
|
||||
p->RemoveGroup(this);
|
||||
state->RemoveGroup(this);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
|
|
@ -1730,18 +1731,18 @@ void Group::ResetInstances(InstanceResetMethod method, bool isRaid, Player* Send
|
|||
InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, Player* player)
|
||||
{
|
||||
MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
|
||||
if(!mapEntry)
|
||||
if (!mapEntry)
|
||||
return NULL;
|
||||
|
||||
Difficulty difficulty = player->GetDifficulty(mapEntry->IsRaid());
|
||||
|
||||
// some instances only have one difficulty
|
||||
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty);
|
||||
if(!mapDiff)
|
||||
if (!mapDiff)
|
||||
difficulty = DUNGEON_DIFFICULTY_NORMAL;
|
||||
|
||||
BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
|
||||
if(itr != m_boundInstances[difficulty].end())
|
||||
if (itr != m_boundInstances[difficulty].end())
|
||||
return &itr->second;
|
||||
else
|
||||
return NULL;
|
||||
|
|
@ -1751,45 +1752,45 @@ InstanceGroupBind* Group::GetBoundInstance(Map* aMap, Difficulty difficulty)
|
|||
{
|
||||
// some instances only have one difficulty
|
||||
MapDifficulty const* mapDiff = GetMapDifficultyData(aMap->GetId(),difficulty);
|
||||
if(!mapDiff)
|
||||
if (!mapDiff)
|
||||
return NULL;
|
||||
|
||||
BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(aMap->GetId());
|
||||
if(itr != m_boundInstances[difficulty].end())
|
||||
if (itr != m_boundInstances[difficulty].end())
|
||||
return &itr->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InstanceGroupBind* Group::BindToInstance(InstanceSave *save, bool permanent, bool load)
|
||||
InstanceGroupBind* Group::BindToInstance(DungeonPersistentState *state, bool permanent, bool load)
|
||||
{
|
||||
if (save && !isBGGroup())
|
||||
if (state && !isBGGroup())
|
||||
{
|
||||
InstanceGroupBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()];
|
||||
if (bind.save)
|
||||
InstanceGroupBind& bind = m_boundInstances[state->GetDifficulty()][state->GetMapId()];
|
||||
if (bind.state)
|
||||
{
|
||||
// when a boss is killed or when copying the players's binds to the group
|
||||
if (permanent != bind.perm || save != bind.save)
|
||||
if (permanent != bind.perm || state != bind.state)
|
||||
if (!load)
|
||||
CharacterDatabase.PExecute("UPDATE group_instance SET instance = '%u', permanent = '%u' WHERE leaderGuid = '%u' AND instance = '%u'",
|
||||
save->GetInstanceId(), permanent, GetLeaderGuid().GetCounter(), bind.save->GetInstanceId());
|
||||
state->GetInstanceId(), permanent, GetLeaderGuid().GetCounter(), bind.state->GetInstanceId());
|
||||
}
|
||||
else if (!load)
|
||||
CharacterDatabase.PExecute("INSERT INTO group_instance (leaderGuid, instance, permanent) VALUES ('%u', '%u', '%u')",
|
||||
GetLeaderGuid().GetCounter(), save->GetInstanceId(), permanent);
|
||||
GetLeaderGuid().GetCounter(), state->GetInstanceId(), permanent);
|
||||
|
||||
if(bind.save != save)
|
||||
if (bind.state != state)
|
||||
{
|
||||
if(bind.save)
|
||||
bind.save->RemoveGroup(this);
|
||||
save->AddGroup(this);
|
||||
if (bind.state)
|
||||
bind.state->RemoveGroup(this);
|
||||
state->AddGroup(this);
|
||||
}
|
||||
|
||||
bind.save = save;
|
||||
bind.state = state;
|
||||
bind.perm = permanent;
|
||||
if (!load)
|
||||
DEBUG_LOG("Group::BindToInstance: Group (Id: %d) is now bound to map %d, instance %d, difficulty %d",
|
||||
GetId(), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty());
|
||||
GetId(), state->GetMapId(), state->GetInstanceId(), state->GetDifficulty());
|
||||
return &bind;
|
||||
}
|
||||
else
|
||||
|
|
@ -1803,8 +1804,8 @@ void Group::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload)
|
|||
{
|
||||
if (!unload)
|
||||
CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderGuid = '%u' AND instance = '%u'",
|
||||
GetLeaderGuid().GetCounter(), itr->second.save->GetInstanceId());
|
||||
itr->second.save->RemoveGroup(this); // save can become invalid
|
||||
GetLeaderGuid().GetCounter(), itr->second.state->GetInstanceId());
|
||||
itr->second.state->RemoveGroup(this); // state can become invalid
|
||||
m_boundInstances[difficulty].erase(itr);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct ItemPrototype;
|
|||
class WorldSession;
|
||||
class Map;
|
||||
class BattleGround;
|
||||
class InstanceSave;
|
||||
class DungeonPersistentState;
|
||||
class Field;
|
||||
class Unit;
|
||||
|
||||
|
|
@ -177,11 +177,11 @@ class Roll : public LootValidatorRef
|
|||
|
||||
struct InstanceGroupBind
|
||||
{
|
||||
InstanceSave *save;
|
||||
DungeonPersistentState *state;
|
||||
bool perm;
|
||||
/* permanent InstanceGroupBinds exist iff the leader has a permanent
|
||||
PlayerInstanceBind for the same instance. */
|
||||
InstanceGroupBind() : save(NULL), perm(false) {}
|
||||
InstanceGroupBind() : state(NULL), perm(false) {}
|
||||
};
|
||||
|
||||
/** request member stats checken **/
|
||||
|
|
@ -356,7 +356,7 @@ class MANGOS_DLL_SPEC Group
|
|||
void LinkMember(GroupReference *pRef) { m_memberMgr.insertFirst(pRef); }
|
||||
void DelinkMember(GroupReference* /*pRef*/ ) { }
|
||||
|
||||
InstanceGroupBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false);
|
||||
InstanceGroupBind* BindToInstance(DungeonPersistentState *save, bool permanent, bool load = false);
|
||||
void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false);
|
||||
InstanceGroupBind* GetBoundInstance(uint32 mapId, Player* player);
|
||||
InstanceGroupBind* GetBoundInstance(Map* aMap, Difficulty difficulty);
|
||||
|
|
|
|||
|
|
@ -35,113 +35,47 @@
|
|||
#include "InstanceData.h"
|
||||
#include "ProgressBar.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1( InstanceSaveManager );
|
||||
INSTANTIATE_SINGLETON_1( MapPersistentStateManager );
|
||||
|
||||
static uint32 resetEventTypeDelay[MAX_RESET_EVENT_TYPE] = { 0, 3600, 900, 300, 60 };
|
||||
|
||||
//== InstanceSave functions ================================
|
||||
//== MapPersistentState functions ==========================
|
||||
|
||||
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_usedByMap(false)
|
||||
MapPersistentState::MapPersistentState(uint16 MapId, uint32 InstanceId, Difficulty difficulty)
|
||||
: m_instanceid(InstanceId), m_mapid(MapId),
|
||||
m_difficulty(difficulty), m_usedByMap(false)
|
||||
{
|
||||
}
|
||||
|
||||
InstanceSave::~InstanceSave()
|
||||
MapPersistentState::~MapPersistentState()
|
||||
{
|
||||
while(!m_playerList.empty())
|
||||
{
|
||||
Player *player = *(m_playerList.begin());
|
||||
player->UnbindInstance(GetMapId(), GetDifficulty(), true);
|
||||
}
|
||||
while(!m_groupList.empty())
|
||||
{
|
||||
Group *group = *(m_groupList.begin());
|
||||
group->UnbindInstance(GetMapId(), GetDifficulty(), true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Called from AddInstanceSave
|
||||
*/
|
||||
void InstanceSave::SaveToDB()
|
||||
{
|
||||
// save instance data too
|
||||
std::string data;
|
||||
|
||||
if (Map *map = sMapMgr.FindMap(GetMapId(),m_instanceid))
|
||||
{
|
||||
InstanceData *iData = map->GetInstanceData();
|
||||
if(iData && iData->Save())
|
||||
{
|
||||
data = iData->Save();
|
||||
CharacterDatabase.escape_string(data);
|
||||
}
|
||||
}
|
||||
|
||||
if (GetMapEntry()->IsDungeon())
|
||||
CharacterDatabase.PExecute("INSERT INTO instance VALUES ('%u', '%u', '"UI64FMTD"', '%u', '%s')", m_instanceid, GetMapId(), (uint64)GetResetTimeForDB(), GetDifficulty(), data.c_str());
|
||||
}
|
||||
|
||||
time_t InstanceSave::GetResetTimeForDB() const
|
||||
{
|
||||
// only save the reset time for normal instances
|
||||
const MapEntry *entry = sMapStore.LookupEntry(GetMapId());
|
||||
if(!entry || entry->map_type == MAP_RAID || GetDifficulty() == DUNGEON_DIFFICULTY_HEROIC)
|
||||
return 0;
|
||||
else
|
||||
return GetResetTime();
|
||||
}
|
||||
|
||||
// to cache or not to cache, that is the question
|
||||
InstanceTemplate const* InstanceSave::GetTemplate() const
|
||||
{
|
||||
return ObjectMgr::GetInstanceTemplate(m_mapid);
|
||||
}
|
||||
|
||||
MapEntry const* InstanceSave::GetMapEntry() const
|
||||
MapEntry const* MapPersistentState::GetMapEntry() const
|
||||
{
|
||||
return sMapStore.LookupEntry(m_mapid);
|
||||
}
|
||||
|
||||
void InstanceSave::DeleteFromDB()
|
||||
bool MapPersistentState::CanBeUnload() const
|
||||
{
|
||||
if (GetMapEntry()->IsDungeon())
|
||||
InstanceSaveManager::DeleteInstanceFromDB(GetInstanceId());
|
||||
// prevent unload if used for loaded map
|
||||
// prevent unload if respawn data still exist (will not prevent reset by scheduler)
|
||||
return !m_usedByMap && m_creatureRespawnTimes.empty() && m_goRespawnTimes.empty();
|
||||
}
|
||||
|
||||
void InstanceSave::DeleteRespawnTimes()
|
||||
/* true if the instance state is still valid */
|
||||
bool MapPersistentState::UnloadIfEmpty()
|
||||
{
|
||||
// possible reset for instanceable map only
|
||||
if (!GetMapEntry()->IsDungeon())
|
||||
return;
|
||||
|
||||
m_goRespawnTimes.clear();
|
||||
m_creatureRespawnTimes.clear();
|
||||
|
||||
CharacterDatabase.BeginTransaction();
|
||||
CharacterDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'", m_instanceid);
|
||||
CharacterDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", m_instanceid);
|
||||
CharacterDatabase.CommitTransaction();
|
||||
}
|
||||
|
||||
/* true if the instance save is still valid */
|
||||
bool InstanceSave::UnloadIfEmpty()
|
||||
{
|
||||
// prevent unload if any bounded groups or online bounded player still exists
|
||||
// also prevent unload if respawn data still exist (will not prevent reset by scheduler)
|
||||
// BGs/Arenas not locked by respawn data
|
||||
if (m_playerList.empty() && m_groupList.empty() && !m_usedByMap &&
|
||||
(GetMapEntry()->IsBattleGroundOrArena() || m_creatureRespawnTimes.empty() && m_goRespawnTimes.empty()))
|
||||
if (CanBeUnload())
|
||||
{
|
||||
sInstanceSaveMgr.RemoveInstanceSave(GetMapId(), GetInstanceId());
|
||||
sMapPersistentStateMgr.RemovePersistentState(GetMapId(), GetInstanceId());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstanceSave::SaveCreatureRespawnTime(uint32 loguid, time_t t)
|
||||
void MapPersistentState::SaveCreatureRespawnTime(uint32 loguid, time_t t)
|
||||
{
|
||||
SetCreatureRespawnTime(loguid, t);
|
||||
|
||||
|
|
@ -156,7 +90,7 @@ void InstanceSave::SaveCreatureRespawnTime(uint32 loguid, time_t t)
|
|||
CharacterDatabase.CommitTransaction();
|
||||
}
|
||||
|
||||
void InstanceSave::SaveGORespawnTime(uint32 loguid, time_t t)
|
||||
void MapPersistentState::SaveGORespawnTime(uint32 loguid, time_t t)
|
||||
{
|
||||
SetGORespawnTime(loguid, t);
|
||||
|
||||
|
|
@ -171,7 +105,7 @@ void InstanceSave::SaveGORespawnTime(uint32 loguid, time_t t)
|
|||
CharacterDatabase.CommitTransaction();
|
||||
}
|
||||
|
||||
void InstanceSave::SetCreatureRespawnTime( uint32 loguid, time_t t )
|
||||
void MapPersistentState::SetCreatureRespawnTime( uint32 loguid, time_t t )
|
||||
{
|
||||
if (t > sWorld.GetGameTime())
|
||||
m_creatureRespawnTimes[loguid] = t;
|
||||
|
|
@ -182,7 +116,7 @@ void InstanceSave::SetCreatureRespawnTime( uint32 loguid, time_t t )
|
|||
}
|
||||
}
|
||||
|
||||
void InstanceSave::SetGORespawnTime( uint32 loguid, time_t t )
|
||||
void MapPersistentState::SetGORespawnTime( uint32 loguid, time_t t )
|
||||
{
|
||||
if (t > sWorld.GetGameTime())
|
||||
m_goRespawnTimes[loguid] = t;
|
||||
|
|
@ -193,9 +127,107 @@ void InstanceSave::SetGORespawnTime( uint32 loguid, time_t t )
|
|||
}
|
||||
}
|
||||
|
||||
//== InstanceResetScheduler functions ======================
|
||||
void MapPersistentState::ClearRespawnTimes()
|
||||
{
|
||||
m_goRespawnTimes.clear();
|
||||
m_creatureRespawnTimes.clear();
|
||||
|
||||
uint32 InstanceResetScheduler::GetMaxResetTimeFor(MapDifficulty const* mapDiff)
|
||||
UnloadIfEmpty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//== DungeonPersistentState functions =====================
|
||||
|
||||
DungeonPersistentState::DungeonPersistentState( uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset )
|
||||
: MapPersistentState(MapId, InstanceId, difficulty), m_resetTime(resetTime), m_canReset(canReset)
|
||||
{
|
||||
}
|
||||
|
||||
DungeonPersistentState::~DungeonPersistentState()
|
||||
{
|
||||
while(!m_playerList.empty())
|
||||
{
|
||||
Player *player = *(m_playerList.begin());
|
||||
player->UnbindInstance(GetMapId(), GetDifficulty(), true);
|
||||
}
|
||||
while(!m_groupList.empty())
|
||||
{
|
||||
Group *group = *(m_groupList.begin());
|
||||
group->UnbindInstance(GetMapId(), GetDifficulty(), true);
|
||||
}
|
||||
}
|
||||
|
||||
bool DungeonPersistentState::CanBeUnload() const
|
||||
{
|
||||
// prevent unload if any bounded groups or online bounded player still exists
|
||||
return MapPersistentState::CanBeUnload() && m_playerList.empty() && m_groupList.empty();
|
||||
}
|
||||
|
||||
/*
|
||||
Called from AddPersistentState
|
||||
*/
|
||||
void DungeonPersistentState::SaveToDB()
|
||||
{
|
||||
// state instance data too
|
||||
std::string data;
|
||||
|
||||
if (Map *map = sMapMgr.FindMap(GetMapId(), GetInstanceId()))
|
||||
{
|
||||
InstanceData *iData = map->GetInstanceData();
|
||||
if(iData && iData->Save())
|
||||
{
|
||||
data = iData->Save();
|
||||
CharacterDatabase.escape_string(data);
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabase.PExecute("INSERT INTO instance VALUES ('%u', '%u', '"UI64FMTD"', '%u', '%s')", GetInstanceId(), GetMapId(), (uint64)GetResetTimeForDB(), GetDifficulty(), data.c_str());
|
||||
}
|
||||
|
||||
void DungeonPersistentState::DeleteRespawnTimes()
|
||||
{
|
||||
CharacterDatabase.BeginTransaction();
|
||||
CharacterDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'", GetInstanceId());
|
||||
CharacterDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", GetInstanceId());
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
ClearRespawnTimes();
|
||||
}
|
||||
|
||||
void DungeonPersistentState::DeleteFromDB()
|
||||
{
|
||||
MapPersistentStateManager::DeleteInstanceFromDB(GetInstanceId());
|
||||
}
|
||||
|
||||
// to cache or not to cache, that is the question
|
||||
InstanceTemplate const* DungeonPersistentState::GetTemplate() const
|
||||
{
|
||||
return ObjectMgr::GetInstanceTemplate(GetMapId());
|
||||
}
|
||||
|
||||
time_t DungeonPersistentState::GetResetTimeForDB() const
|
||||
{
|
||||
// only state the reset time for normal instances
|
||||
const MapEntry *entry = sMapStore.LookupEntry(GetMapId());
|
||||
if(!entry || entry->map_type == MAP_RAID || GetDifficulty() == DUNGEON_DIFFICULTY_HEROIC)
|
||||
return 0;
|
||||
else
|
||||
return GetResetTime();
|
||||
}
|
||||
|
||||
//== BattleGroundPersistentState functions =================
|
||||
|
||||
bool BattleGroundPersistentState::CanBeUnload() const
|
||||
{
|
||||
// prevent unload if used for loaded map
|
||||
// BGs/Arenas not locked by respawn data/etc
|
||||
return !IsUsedByMap();
|
||||
}
|
||||
|
||||
//== DungeonResetScheduler functions ======================
|
||||
|
||||
uint32 DungeonResetScheduler::GetMaxResetTimeFor(MapDifficulty const* mapDiff)
|
||||
{
|
||||
if (!mapDiff || !mapDiff->resetTime)
|
||||
return 0;
|
||||
|
|
@ -208,14 +240,14 @@ uint32 InstanceResetScheduler::GetMaxResetTimeFor(MapDifficulty const* mapDiff)
|
|||
return delay;
|
||||
}
|
||||
|
||||
time_t InstanceResetScheduler::CalculateNextResetTime(MapDifficulty const* mapDiff, time_t prevResetTime)
|
||||
time_t DungeonResetScheduler::CalculateNextResetTime(MapDifficulty const* mapDiff, time_t prevResetTime)
|
||||
{
|
||||
uint32 diff = sWorld.getConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR) * HOUR;
|
||||
uint32 period = GetMaxResetTimeFor(mapDiff);
|
||||
return ((prevResetTime + MINUTE) / DAY * DAY) + period + diff;
|
||||
}
|
||||
|
||||
void InstanceResetScheduler::LoadResetTimes()
|
||||
void DungeonResetScheduler::LoadResetTimes()
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
time_t today = (now / DAY) * DAY;
|
||||
|
|
@ -268,7 +300,7 @@ void InstanceResetScheduler::LoadResetTimes()
|
|||
// schedule the reset times
|
||||
for(InstResetTimeMapDiffType::iterator itr = instResetTime.begin(); itr != instResetTime.end(); ++itr)
|
||||
if(itr->second.second > now)
|
||||
ScheduleReset(true, itr->second.second, InstanceResetEvent(RESET_EVENT_DUNGEON, PAIR32_LOPART(itr->second.first),Difficulty(PAIR32_HIPART(itr->second.first)),itr->first));
|
||||
ScheduleReset(true, itr->second.second, DungeonResetEvent(RESET_EVENT_NORMAL_DUNGEON, PAIR32_LOPART(itr->second.first),Difficulty(PAIR32_HIPART(itr->second.first)),itr->first));
|
||||
}
|
||||
|
||||
// load the global respawn times for raid/heroic instances
|
||||
|
|
@ -286,7 +318,7 @@ void InstanceResetScheduler::LoadResetTimes()
|
|||
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty);
|
||||
if(!mapDiff)
|
||||
{
|
||||
sLog.outError("InstanceSaveManager::LoadResetTimes: invalid mapid(%u)/difficulty(%u) pair in instance_reset!", mapid, difficulty);
|
||||
sLog.outError("MapPersistentStateManager::LoadResetTimes: invalid mapid(%u)/difficulty(%u) pair in instance_reset!", mapid, difficulty);
|
||||
CharacterDatabase.DirectPExecute("DELETE FROM instance_reset WHERE mapid = '%u' AND difficulty = '%u'", mapid,difficulty);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -344,14 +376,14 @@ void InstanceResetScheduler::LoadResetTimes()
|
|||
if(t - resetEventTypeDelay[type] > now)
|
||||
break;
|
||||
|
||||
ScheduleReset(true, t - resetEventTypeDelay[type], InstanceResetEvent(type, mapid, difficulty, 0));
|
||||
ScheduleReset(true, t - resetEventTypeDelay[type], DungeonResetEvent(type, mapid, difficulty, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceResetScheduler::ScheduleReset(bool add, time_t time, InstanceResetEvent event)
|
||||
void DungeonResetScheduler::ScheduleReset(bool add, time_t time, DungeonResetEvent event)
|
||||
{
|
||||
if (add)
|
||||
m_resetTimeQueue.insert(std::pair<time_t, InstanceResetEvent>(time, event));
|
||||
m_resetTimeQueue.insert(std::pair<time_t, DungeonResetEvent>(time, event));
|
||||
else
|
||||
{
|
||||
// find the event in the queue and remove it
|
||||
|
|
@ -379,18 +411,18 @@ void InstanceResetScheduler::ScheduleReset(bool add, time_t time, InstanceResetE
|
|||
}
|
||||
|
||||
if(itr == m_resetTimeQueue.end())
|
||||
sLog.outError("InstanceResetScheduler::ScheduleReset: cannot cancel the reset, the event(%d,%d,%d) was not found!", event.type, event.mapid, event.instanceId);
|
||||
sLog.outError("DungeonResetScheduler::ScheduleReset: cannot cancel the reset, the event(%d,%d,%d) was not found!", event.type, event.mapid, event.instanceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceResetScheduler::Update()
|
||||
void DungeonResetScheduler::Update()
|
||||
{
|
||||
time_t now = time(NULL), t;
|
||||
while(!m_resetTimeQueue.empty() && (t = m_resetTimeQueue.begin()->first) < now)
|
||||
{
|
||||
InstanceResetEvent &event = m_resetTimeQueue.begin()->second;
|
||||
if (event.type == RESET_EVENT_DUNGEON)
|
||||
DungeonResetEvent &event = m_resetTimeQueue.begin()->second;
|
||||
if (event.type == RESET_EVENT_NORMAL_DUNGEON)
|
||||
{
|
||||
// for individual normal instances, max creature respawn + X hours
|
||||
m_InstanceSaves._ResetInstance(event.mapid, event.instanceId);
|
||||
|
|
@ -413,7 +445,7 @@ void InstanceResetScheduler::Update()
|
|||
MapDifficulty const* mapDiff = GetMapDifficultyData(event.mapid,event.difficulty);
|
||||
MANGOS_ASSERT(mapDiff);
|
||||
|
||||
time_t next_reset = InstanceResetScheduler::CalculateNextResetTime(mapDiff, resetTime);
|
||||
time_t next_reset = DungeonResetScheduler::CalculateNextResetTime(mapDiff, resetTime);
|
||||
|
||||
CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty = '%u'", uint64(next_reset), uint32(event.mapid), uint32(event.difficulty));
|
||||
|
||||
|
|
@ -433,30 +465,30 @@ void InstanceResetScheduler::Update()
|
|||
}
|
||||
}
|
||||
|
||||
//== InstanceSaveManager functions =========================
|
||||
//== MapPersistentStateManager functions =========================
|
||||
|
||||
InstanceSaveManager::InstanceSaveManager() : lock_instLists(false), m_Scheduler(*this)
|
||||
MapPersistentStateManager::MapPersistentStateManager() : lock_instLists(false), m_Scheduler(*this)
|
||||
{
|
||||
}
|
||||
|
||||
InstanceSaveManager::~InstanceSaveManager()
|
||||
MapPersistentStateManager::~MapPersistentStateManager()
|
||||
{
|
||||
// it is undefined whether this or objectmgr will be unloaded first
|
||||
// so we must be prepared for both cases
|
||||
lock_instLists = true;
|
||||
for (InstanceSaveHashMap::iterator itr = m_instanceSaveByInstanceId.begin(); itr != m_instanceSaveByInstanceId.end(); ++itr)
|
||||
for (PersistentStateMap::iterator itr = m_instanceSaveByInstanceId.begin(); itr != m_instanceSaveByInstanceId.end(); ++itr)
|
||||
delete itr->second;
|
||||
for (InstanceSaveHashMap::iterator itr = m_instanceSaveByMapId.begin(); itr != m_instanceSaveByMapId.end(); ++itr)
|
||||
for (PersistentStateMap::iterator itr = m_instanceSaveByMapId.begin(); itr != m_instanceSaveByMapId.end(); ++itr)
|
||||
delete itr->second;
|
||||
}
|
||||
|
||||
/*
|
||||
- adding instance into manager
|
||||
- called from InstanceMap::Add, _LoadBoundInstances, LoadGroups
|
||||
- called from DungeonMap::Add, _LoadBoundInstances, LoadGroups
|
||||
*/
|
||||
InstanceSave* InstanceSaveManager::AddInstanceSave(MapEntry const* mapEntry, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load)
|
||||
MapPersistentState* MapPersistentStateManager::AddPersistentState(MapEntry const* mapEntry, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load)
|
||||
{
|
||||
if (InstanceSave *old_save = GetInstanceSave(mapEntry->MapID, instanceId))
|
||||
if (MapPersistentState *old_save = GetPersistentState(mapEntry->MapID, instanceId))
|
||||
return old_save;
|
||||
|
||||
if (mapEntry->IsDungeon())
|
||||
|
|
@ -470,41 +502,51 @@ InstanceSave* InstanceSaveManager::AddInstanceSave(MapEntry const* mapEntry, uin
|
|||
else
|
||||
{
|
||||
resetTime = time(NULL) + 2 * HOUR;
|
||||
// normally this will be removed soon after in InstanceMap::Add, prevent error
|
||||
m_Scheduler.ScheduleReset(true, resetTime, InstanceResetEvent(RESET_EVENT_DUNGEON, mapEntry->MapID, difficulty, instanceId));
|
||||
// normally this will be removed soon after in DungeonMap::Add, prevent error
|
||||
m_Scheduler.ScheduleReset(true, resetTime, DungeonResetEvent(RESET_EVENT_NORMAL_DUNGEON, mapEntry->MapID, difficulty, instanceId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d, reset time = %u, canRset = %u", mapEntry->MapID, instanceId, resetTime, canReset ? 1 : 0);
|
||||
DEBUG_LOG("MapPersistentStateManager::AddPersistentState: mapid = %d, instanceid = %d, reset time = %u, canRset = %u", mapEntry->MapID, instanceId, resetTime, canReset ? 1 : 0);
|
||||
|
||||
InstanceSave *save = new InstanceSave(mapEntry->MapID, instanceId, difficulty, resetTime, canReset);
|
||||
MapPersistentState *state;
|
||||
if (mapEntry->IsDungeon())
|
||||
{
|
||||
DungeonPersistentState* dungeonState = new DungeonPersistentState(mapEntry->MapID, instanceId, difficulty, resetTime, canReset);
|
||||
if (!load)
|
||||
save->SaveToDB();
|
||||
|
||||
if (mapEntry->Instanceable())
|
||||
m_instanceSaveByInstanceId[instanceId] = save;
|
||||
dungeonState->SaveToDB();
|
||||
state = dungeonState;
|
||||
}
|
||||
else if (mapEntry->IsBattleGroundOrArena())
|
||||
state = new BattleGroundPersistentState(mapEntry->MapID, instanceId, difficulty);
|
||||
else
|
||||
m_instanceSaveByMapId[mapEntry->MapID] = save;
|
||||
state = new MapPersistentState(mapEntry->MapID, instanceId, difficulty);
|
||||
|
||||
return save;
|
||||
|
||||
if (instanceId)
|
||||
m_instanceSaveByInstanceId[instanceId] = state;
|
||||
else
|
||||
m_instanceSaveByMapId[mapEntry->MapID] = state;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
InstanceSave *InstanceSaveManager::GetInstanceSave(uint32 mapId, uint32 instanceId)
|
||||
MapPersistentState *MapPersistentStateManager::GetPersistentState(uint32 mapId, uint32 instanceId)
|
||||
{
|
||||
if (instanceId)
|
||||
{
|
||||
InstanceSaveHashMap::iterator itr = m_instanceSaveByInstanceId.find(instanceId);
|
||||
PersistentStateMap::iterator itr = m_instanceSaveByInstanceId.find(instanceId);
|
||||
return itr != m_instanceSaveByInstanceId.end() ? itr->second : NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
InstanceSaveHashMap::iterator itr = m_instanceSaveByMapId.find(mapId);
|
||||
PersistentStateMap::iterator itr = m_instanceSaveByMapId.find(mapId);
|
||||
return itr != m_instanceSaveByMapId.end() ? itr->second : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSaveManager::DeleteInstanceFromDB(uint32 instanceid)
|
||||
void MapPersistentStateManager::DeleteInstanceFromDB(uint32 instanceid)
|
||||
{
|
||||
if (instanceid)
|
||||
{
|
||||
|
|
@ -518,19 +560,19 @@ void InstanceSaveManager::DeleteInstanceFromDB(uint32 instanceid)
|
|||
}
|
||||
}
|
||||
|
||||
void InstanceSaveManager::RemoveInstanceSave(uint32 mapId, uint32 instanceId)
|
||||
void MapPersistentStateManager::RemovePersistentState(uint32 mapId, uint32 instanceId)
|
||||
{
|
||||
if (lock_instLists)
|
||||
return;
|
||||
|
||||
if (instanceId)
|
||||
{
|
||||
InstanceSaveHashMap::iterator itr = m_instanceSaveByInstanceId.find(instanceId);
|
||||
PersistentStateMap::iterator itr = m_instanceSaveByInstanceId.find(instanceId);
|
||||
if (itr != m_instanceSaveByInstanceId.end())
|
||||
{
|
||||
// save the resettime for normal instances only when they get unloaded
|
||||
// state the resettime for normal instances only when they get unloaded
|
||||
if (itr->second->GetMapEntry()->IsDungeon())
|
||||
if (time_t resettime = itr->second->GetResetTimeForDB())
|
||||
if (time_t resettime = ((DungeonPersistentState*)itr->second)->GetResetTimeForDB())
|
||||
CharacterDatabase.PExecute("UPDATE instance SET resettime = '"UI64FMTD"' WHERE id = '%u'", (uint64)resettime, instanceId);
|
||||
|
||||
_ResetSave(m_instanceSaveByInstanceId, itr);
|
||||
|
|
@ -538,13 +580,13 @@ void InstanceSaveManager::RemoveInstanceSave(uint32 mapId, uint32 instanceId)
|
|||
}
|
||||
else
|
||||
{
|
||||
InstanceSaveHashMap::iterator itr = m_instanceSaveByMapId.find(mapId);
|
||||
PersistentStateMap::iterator itr = m_instanceSaveByMapId.find(mapId);
|
||||
if (itr != m_instanceSaveByMapId.end())
|
||||
_ResetSave(m_instanceSaveByMapId, itr);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSaveManager::_DelHelper(DatabaseType &db, const char *fields, const char *table, const char *queryTail,...)
|
||||
void MapPersistentStateManager::_DelHelper(DatabaseType &db, const char *fields, const char *table, const char *queryTail,...)
|
||||
{
|
||||
Tokens fieldTokens = StrSplit(fields, ", ");
|
||||
MANGOS_ASSERT(fieldTokens.size() != 0);
|
||||
|
|
@ -574,7 +616,7 @@ void InstanceSaveManager::_DelHelper(DatabaseType &db, const char *fields, const
|
|||
}
|
||||
}
|
||||
|
||||
void InstanceSaveManager::CleanupInstances()
|
||||
void MapPersistentStateManager::CleanupInstances()
|
||||
{
|
||||
barGoLink bar(2);
|
||||
bar.step();
|
||||
|
|
@ -605,7 +647,7 @@ void InstanceSaveManager::CleanupInstances()
|
|||
sLog.outString( ">> Instances cleaned up");
|
||||
}
|
||||
|
||||
void InstanceSaveManager::PackInstances()
|
||||
void MapPersistentStateManager::PackInstances()
|
||||
{
|
||||
// this routine renumbers player instance associations in such a way so they start from 1 and go up
|
||||
// TODO: this can be done a LOT more efficiently
|
||||
|
|
@ -657,7 +699,7 @@ void InstanceSaveManager::PackInstances()
|
|||
sLog.outString();
|
||||
}
|
||||
|
||||
void InstanceSaveManager::_ResetSave(InstanceSaveHashMap& holder, InstanceSaveHashMap::iterator &itr)
|
||||
void MapPersistentStateManager::_ResetSave(PersistentStateMap& holder, PersistentStateMap::iterator &itr)
|
||||
{
|
||||
// unbind all players bound to the instance
|
||||
// do not allow UnbindInstance to automatically unload the InstanceSaves
|
||||
|
|
@ -667,24 +709,24 @@ void InstanceSaveManager::_ResetSave(InstanceSaveHashMap& holder, InstanceSaveHa
|
|||
lock_instLists = false;
|
||||
}
|
||||
|
||||
void InstanceSaveManager::_ResetInstance(uint32 mapid, uint32 instanceId)
|
||||
void MapPersistentStateManager::_ResetInstance(uint32 mapid, uint32 instanceId)
|
||||
{
|
||||
DEBUG_LOG("InstanceSaveMgr::_ResetInstance %u, %u", mapid, instanceId);
|
||||
Map * iMap = sMapMgr.FindMap(mapid, instanceId);
|
||||
if (!iMap || !iMap->Instanceable())
|
||||
return;
|
||||
|
||||
InstanceSaveHashMap::iterator itr = m_instanceSaveByInstanceId.find(instanceId);
|
||||
PersistentStateMap::iterator itr = m_instanceSaveByInstanceId.find(instanceId);
|
||||
if (itr != m_instanceSaveByInstanceId.end())
|
||||
_ResetSave(m_instanceSaveByInstanceId, itr);
|
||||
|
||||
DeleteInstanceFromDB(instanceId); // even if save not loaded
|
||||
DeleteInstanceFromDB(instanceId); // even if state not loaded
|
||||
|
||||
if (iMap->IsDungeon())
|
||||
((InstanceMap*)iMap)->Reset(INSTANCE_RESET_RESPAWN_DELAY);
|
||||
((DungeonMap*)iMap)->Reset(INSTANCE_RESET_RESPAWN_DELAY);
|
||||
}
|
||||
|
||||
void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeLeft)
|
||||
void MapPersistentStateManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeLeft)
|
||||
{
|
||||
// global reset for all instances of the given map
|
||||
MapEntry const *mapEntry = sMapStore.LookupEntry(mapid);
|
||||
|
|
@ -698,12 +740,12 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b
|
|||
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty);
|
||||
if (!mapDiff || !mapDiff->resetTime)
|
||||
{
|
||||
sLog.outError("InstanceSaveManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid);
|
||||
sLog.outError("MapPersistentStateManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid);
|
||||
return;
|
||||
}
|
||||
|
||||
// remove all binds to instances of the given map
|
||||
for(InstanceSaveHashMap::iterator itr = m_instanceSaveByInstanceId.begin(); itr != m_instanceSaveByInstanceId.end();)
|
||||
for(PersistentStateMap::iterator itr = m_instanceSaveByInstanceId.begin(); itr != m_instanceSaveByInstanceId.end();)
|
||||
{
|
||||
if (itr->second->GetMapId() == mapid && itr->second->GetDifficulty() == difficulty)
|
||||
_ResetSave(m_instanceSaveByInstanceId, itr);
|
||||
|
|
@ -719,7 +761,7 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b
|
|||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
// calculate the next reset time
|
||||
time_t next_reset = InstanceResetScheduler::CalculateNextResetTime(mapDiff, now + timeLeft);
|
||||
time_t next_reset = DungeonResetScheduler::CalculateNextResetTime(mapDiff, now + timeLeft);
|
||||
// update it in the DB
|
||||
CharacterDatabase.PExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty = '%u'", (uint64)next_reset, mapid, difficulty);
|
||||
}
|
||||
|
|
@ -735,38 +777,38 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b
|
|||
break;
|
||||
|
||||
if (warn)
|
||||
((InstanceMap*)map2)->SendResetWarnings(timeLeft);
|
||||
((DungeonMap*)map2)->SendResetWarnings(timeLeft);
|
||||
else
|
||||
((InstanceMap*)map2)->Reset(INSTANCE_RESET_GLOBAL);
|
||||
((DungeonMap*)map2)->Reset(INSTANCE_RESET_GLOBAL);
|
||||
}
|
||||
|
||||
// TODO: delete creature/gameobject respawn times even if the maps are not loaded
|
||||
}
|
||||
|
||||
uint32 InstanceSaveManager::GetNumBoundPlayersTotal()
|
||||
void MapPersistentStateManager::GetStatistics(uint32& numStates, uint32& numBoundPlayers, uint32& numBoundGroups)
|
||||
{
|
||||
uint32 ret = 0;
|
||||
numStates = 0;
|
||||
numBoundPlayers = 0;
|
||||
numBoundGroups = 0;
|
||||
|
||||
// only instanceable maps have bounds
|
||||
for(InstanceSaveHashMap::iterator itr = m_instanceSaveByInstanceId.begin(); itr != m_instanceSaveByInstanceId.end(); ++itr)
|
||||
ret += itr->second->GetPlayerCount();
|
||||
return ret;
|
||||
for(PersistentStateMap::iterator itr = m_instanceSaveByInstanceId.begin(); itr != m_instanceSaveByInstanceId.end(); ++itr)
|
||||
{
|
||||
if (!itr->second->GetMapEntry()->IsDungeon())
|
||||
continue;
|
||||
|
||||
++numStates;
|
||||
numBoundPlayers += ((DungeonPersistentState*)itr->second)->GetPlayerCount();
|
||||
numBoundGroups += ((DungeonPersistentState*)itr->second)->GetGroupCount();
|
||||
}
|
||||
}
|
||||
|
||||
uint32 InstanceSaveManager::GetNumBoundGroupsTotal()
|
||||
{
|
||||
uint32 ret = 0;
|
||||
// only instanceable maps have bounds
|
||||
for(InstanceSaveHashMap::iterator itr = m_instanceSaveByInstanceId.begin(); itr != m_instanceSaveByInstanceId.end(); ++itr)
|
||||
ret += itr->second->GetGroupCount();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void InstanceSaveManager::_CleanupExpiredInstancesAtTime( time_t t )
|
||||
void MapPersistentStateManager::_CleanupExpiredInstancesAtTime( time_t t )
|
||||
{
|
||||
_DelHelper(CharacterDatabase, "id, map, instance.difficulty", "instance", "LEFT JOIN instance_reset ON mapid = map AND instance.difficulty = instance_reset.difficulty WHERE (instance.resettime < '"UI64FMTD"' AND instance.resettime > '0') OR (NOT instance_reset.resettime IS NULL AND instance_reset.resettime < '"UI64FMTD"')", (uint64)t, (uint64)t);
|
||||
}
|
||||
|
||||
void InstanceSaveManager::LoadCreatureRespawnTimes()
|
||||
void MapPersistentStateManager::LoadCreatureRespawnTimes()
|
||||
{
|
||||
// remove outdated data
|
||||
CharacterDatabase.DirectExecute("DELETE FROM creature_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())");
|
||||
|
|
@ -805,15 +847,15 @@ void InstanceSaveManager::LoadCreatureRespawnTimes()
|
|||
if (!mapEntry || (mapEntry->Instanceable() != (instanceId != 0)))
|
||||
continue;
|
||||
|
||||
// instances loaded early and respawn data must exist only for existed instances (save loaded) or non-instanced maps
|
||||
InstanceSave* save = instanceId
|
||||
? GetInstanceSave(data->mapid, instanceId)
|
||||
: AddInstanceSave(mapEntry, 0, REGULAR_DIFFICULTY, 0, false, true);
|
||||
// instances loaded early and respawn data must exist only for existed instances (state loaded) or non-instanced maps
|
||||
MapPersistentState* state = instanceId
|
||||
? GetPersistentState(data->mapid, instanceId)
|
||||
: AddPersistentState(mapEntry, 0, REGULAR_DIFFICULTY, 0, false, true);
|
||||
|
||||
if (!save)
|
||||
if (!state)
|
||||
continue;
|
||||
|
||||
save->SetCreatureRespawnTime(loguid, time_t(respawn_time));
|
||||
state->SetCreatureRespawnTime(loguid, time_t(respawn_time));
|
||||
|
||||
++count;
|
||||
|
||||
|
|
@ -825,7 +867,7 @@ void InstanceSaveManager::LoadCreatureRespawnTimes()
|
|||
sLog.outString();
|
||||
}
|
||||
|
||||
void InstanceSaveManager::LoadGameobjectRespawnTimes()
|
||||
void MapPersistentStateManager::LoadGameobjectRespawnTimes()
|
||||
{
|
||||
// remove outdated data
|
||||
CharacterDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())");
|
||||
|
|
@ -865,15 +907,15 @@ void InstanceSaveManager::LoadGameobjectRespawnTimes()
|
|||
if (!mapEntry || (mapEntry->Instanceable() != (instanceId != 0)))
|
||||
continue;
|
||||
|
||||
// instances loaded early and respawn data must exist only for existed instances (save loaded) or non-instanced maps
|
||||
InstanceSave* save = instanceId
|
||||
? GetInstanceSave(data->mapid, instanceId)
|
||||
: AddInstanceSave(mapEntry, 0, REGULAR_DIFFICULTY, 0, false, true);
|
||||
// instances loaded early and respawn data must exist only for existed instances (state loaded) or non-instanced maps
|
||||
MapPersistentState* state = instanceId
|
||||
? GetPersistentState(data->mapid, instanceId)
|
||||
: AddPersistentState(mapEntry, 0, REGULAR_DIFFICULTY, 0, false, true);
|
||||
|
||||
if (!save)
|
||||
if (!state)
|
||||
continue;
|
||||
|
||||
save->SetGORespawnTime(loguid, time_t(respawn_time));
|
||||
state->SetGORespawnTime(loguid, time_t(respawn_time));
|
||||
|
||||
++count;
|
||||
|
||||
|
|
|
|||
|
|
@ -36,71 +36,41 @@ struct MapDifficulty;
|
|||
class Player;
|
||||
class Group;
|
||||
|
||||
class InstanceSaveManager;
|
||||
class MapPersistentStateManager;
|
||||
|
||||
/*
|
||||
Holds the information necessary for creating a new map for an existing instance
|
||||
Is referenced in three cases:
|
||||
- player-instance binds for solo players (not in group)
|
||||
- player-instance binds for permanent heroic/raid saves
|
||||
- group-instance binds (both solo and permanent) cache the player binds for the group leader
|
||||
Holds the information necessary for creating a new map for non-instanceable maps
|
||||
|
||||
As object Used for non-instanceable Map only
|
||||
*/
|
||||
class InstanceSave
|
||||
class MapPersistentState
|
||||
{
|
||||
friend class InstanceSaveManager;
|
||||
friend class MapPersistentStateManager;
|
||||
public:
|
||||
/* Created either when:
|
||||
- any new instance is being generated
|
||||
- the first time a player bound to InstanceId logs in
|
||||
- when a group bound to the instance is loaded */
|
||||
InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset);
|
||||
MapPersistentState(uint16 MapId, uint32 InstanceId, Difficulty difficulty);
|
||||
|
||||
/* Unloaded when m_playerList and m_groupList become empty
|
||||
or when the instance is reset */
|
||||
~InstanceSave();
|
||||
|
||||
uint8 GetPlayerCount() const { return m_playerList.size(); }
|
||||
uint8 GetGroupCount() const { return m_groupList.size(); }
|
||||
virtual ~MapPersistentState();
|
||||
|
||||
/* A map corresponding to the InstanceId/MapId does not always exist.
|
||||
InstanceSave objects may be created on player logon but the maps are
|
||||
MapPersistentState objects may be created on player logon but the maps are
|
||||
created and loaded only when a player actually enters the instance. */
|
||||
uint32 GetInstanceId() const { return m_instanceid; }
|
||||
ObjectGuid GetInstanceGuid() const { return ObjectGuid(HIGHGUID_INSTANCE, GetInstanceId()); }
|
||||
uint32 GetMapId() const { return m_mapid; }
|
||||
|
||||
/* Saved when the instance is generated for the first time */
|
||||
void SaveToDB();
|
||||
/* When the instance is being reset (permanently deleted) */
|
||||
void DeleteFromDB();
|
||||
|
||||
/* for normal instances this corresponds to max(creature respawn time) + X hours
|
||||
for raid/heroic instances this caches the global respawn time for the map */
|
||||
time_t GetResetTime() const { return m_resetTime; }
|
||||
void SetResetTime(time_t resetTime) { m_resetTime = resetTime; }
|
||||
time_t GetResetTimeForDB() const;
|
||||
|
||||
InstanceTemplate const* GetTemplate() const;
|
||||
MapEntry const* GetMapEntry() const;
|
||||
|
||||
/* online players bound to the instance (perm/solo)
|
||||
does not include the members of the group unless they have permanent saves */
|
||||
void AddPlayer(Player *player) { m_playerList.push_back(player); }
|
||||
bool RemovePlayer(Player *player) { m_playerList.remove(player); return UnloadIfEmpty(); }
|
||||
/* all groups bound to the instance */
|
||||
void AddGroup(Group *group) { m_groupList.push_back(group); }
|
||||
bool RemoveGroup(Group *group) { m_groupList.remove(group); return UnloadIfEmpty(); }
|
||||
|
||||
/* instances cannot be reset (except at the global reset time)
|
||||
if there are players permanently bound to it
|
||||
this is cached for the case when those players are offline */
|
||||
bool CanReset() const { return m_canReset; }
|
||||
void SetCanReset(bool canReset) { m_canReset = canReset; }
|
||||
|
||||
/* currently it is possible to omit this information from this structure
|
||||
but that would depend on a lot of things that can easily change in future */
|
||||
Difficulty GetDifficulty() const { return m_difficulty; }
|
||||
|
||||
bool IsUsedByMap() const { return m_usedByMap; }
|
||||
void SetUsedByMapState(bool state)
|
||||
{
|
||||
m_usedByMap = state;
|
||||
|
|
@ -108,7 +78,6 @@ class InstanceSave
|
|||
UnloadIfEmpty();
|
||||
}
|
||||
|
||||
void DeleteRespawnTimes();
|
||||
time_t GetCreatureRespawnTime(uint32 loguid) const
|
||||
{
|
||||
RespawnTimes::const_iterator itr = m_creatureRespawnTimes.find(loguid);
|
||||
|
|
@ -122,36 +91,116 @@ class InstanceSave
|
|||
}
|
||||
void SaveGORespawnTime(uint32 loguid, time_t t);
|
||||
|
||||
protected:
|
||||
virtual bool CanBeUnload() const;
|
||||
bool UnloadIfEmpty();
|
||||
void ClearRespawnTimes();
|
||||
|
||||
private:
|
||||
void SetCreatureRespawnTime(uint32 loguid, time_t t);
|
||||
void SetGORespawnTime(uint32 loguid, time_t t);
|
||||
|
||||
private:
|
||||
typedef UNORDERED_MAP<uint32, time_t> RespawnTimes;
|
||||
typedef std::list<Player*> PlayerListType;
|
||||
typedef std::list<Group*> GroupListType;
|
||||
|
||||
bool UnloadIfEmpty();
|
||||
/* the only reason the instSave-object links are kept is because
|
||||
the object-instSave links need to be broken at reset time
|
||||
TODO: maybe it's enough to just store the number of players/groups */
|
||||
PlayerListType m_playerList; // lock InstanceSave from unload
|
||||
GroupListType m_groupList; // lock InstanceSave from unload
|
||||
time_t m_resetTime;
|
||||
uint32 m_instanceid;
|
||||
uint32 m_mapid;
|
||||
Difficulty m_difficulty;
|
||||
bool m_canReset;
|
||||
bool m_usedByMap; // true when instance map loaded, lock InstanceSave from unload
|
||||
bool m_usedByMap; // true when instance map loaded, lock MapPersistentState from unload
|
||||
|
||||
// persistent data
|
||||
RespawnTimes m_creatureRespawnTimes; // // lock InstanceSave from unload, for example for temporary bound dungeon unload delay
|
||||
RespawnTimes m_goRespawnTimes; // lock InstanceSave from unload, for example for temporary bound dungeon unload delay
|
||||
RespawnTimes m_creatureRespawnTimes; // lock MapPersistentState from unload, for example for temporary bound dungeon unload delay
|
||||
RespawnTimes m_goRespawnTimes; // lock MapPersistentState from unload, for example for temporary bound dungeon unload delay
|
||||
};
|
||||
|
||||
/*
|
||||
Holds the information necessary for creating a new map for an existing instance
|
||||
Is referenced in three cases:
|
||||
- player-instance binds for solo players (not in group)
|
||||
- player-instance binds for permanent heroic/raid saves
|
||||
- group-instance binds (both solo and permanent) cache the player binds for the group leader
|
||||
|
||||
Used for InstanceMap only
|
||||
*/
|
||||
class DungeonPersistentState : public MapPersistentState
|
||||
{
|
||||
public:
|
||||
/* Created either when:
|
||||
- any new instance is being generated
|
||||
- the first time a player bound to InstanceId logs in
|
||||
- when a group bound to the instance is loaded */
|
||||
DungeonPersistentState(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset);
|
||||
|
||||
~DungeonPersistentState();
|
||||
|
||||
InstanceTemplate const* GetTemplate() const;
|
||||
|
||||
uint8 GetPlayerCount() const { return m_playerList.size(); }
|
||||
uint8 GetGroupCount() const { return m_groupList.size(); }
|
||||
|
||||
/* online players bound to the instance (perm/solo)
|
||||
does not include the members of the group unless they have permanent saves */
|
||||
void AddPlayer(Player *player) { m_playerList.push_back(player); }
|
||||
bool RemovePlayer(Player *player) { m_playerList.remove(player); return UnloadIfEmpty(); }
|
||||
/* all groups bound to the instance */
|
||||
void AddGroup(Group *group) { m_groupList.push_back(group); }
|
||||
bool RemoveGroup(Group *group) { m_groupList.remove(group); return UnloadIfEmpty(); }
|
||||
|
||||
/* for normal instances this corresponds to max(creature respawn time) + X hours
|
||||
for raid/heroic instances this caches the global respawn time for the map */
|
||||
time_t GetResetTime() const { return m_resetTime; }
|
||||
void SetResetTime(time_t resetTime) { m_resetTime = resetTime; }
|
||||
time_t GetResetTimeForDB() const;
|
||||
|
||||
/* instances cannot be reset (except at the global reset time)
|
||||
if there are players permanently bound to it
|
||||
this is cached for the case when those players are offline */
|
||||
bool CanReset() const { return m_canReset; }
|
||||
void SetCanReset(bool canReset) { m_canReset = canReset; }
|
||||
|
||||
/* Saved when the instance is generated for the first time */
|
||||
void SaveToDB();
|
||||
/* When the instance is being reset (permanently deleted) */
|
||||
void DeleteFromDB();
|
||||
/* Delete respawn data at dungeon reset */
|
||||
void DeleteRespawnTimes();
|
||||
|
||||
protected:
|
||||
bool CanBeUnload() const; // overwrite MapPersistentState::CanBeUnload
|
||||
|
||||
private:
|
||||
typedef std::list<Player*> PlayerListType;
|
||||
typedef std::list<Group*> GroupListType;
|
||||
|
||||
time_t m_resetTime;
|
||||
bool m_canReset;
|
||||
|
||||
/* the only reason the instSave-object links are kept is because
|
||||
the object-instSave links need to be broken at reset time
|
||||
TODO: maybe it's enough to just store the number of players/groups */
|
||||
PlayerListType m_playerList; // lock MapPersistentState from unload
|
||||
GroupListType m_groupList; // lock MapPersistentState from unload
|
||||
};
|
||||
|
||||
class BattleGroundPersistentState : public MapPersistentState
|
||||
{
|
||||
public:
|
||||
/* Created either when:
|
||||
- any new BG/arena is being generated
|
||||
*/
|
||||
BattleGroundPersistentState(uint16 MapId, uint32 InstanceId, Difficulty difficulty)
|
||||
: MapPersistentState(MapId, InstanceId, difficulty) {}
|
||||
|
||||
~BattleGroundPersistentState() {}
|
||||
|
||||
protected:
|
||||
bool CanBeUnload() const; // overwrite MapPersistentState::CanBeUnload
|
||||
};
|
||||
|
||||
|
||||
enum ResetEventType
|
||||
{
|
||||
RESET_EVENT_DUNGEON = 0, // no fixed reset time
|
||||
RESET_EVENT_NORMAL_DUNGEON = 0, // no fixed reset time
|
||||
RESET_EVENT_INFORM_1 = 1, // raid/heroic warnings
|
||||
RESET_EVENT_INFORM_2 = 2,
|
||||
RESET_EVENT_INFORM_3 = 3,
|
||||
|
|
@ -162,23 +211,23 @@ enum ResetEventType
|
|||
|
||||
/* resetTime is a global propery of each (raid/heroic) map
|
||||
all instances of that map reset at the same time */
|
||||
struct InstanceResetEvent
|
||||
struct DungeonResetEvent
|
||||
{
|
||||
ResetEventType type :8; // if RESET_EVENT_DUNGEON then InstanceID == 0 and applied to all instances for pair (map,diff)
|
||||
ResetEventType type :8; // if RESET_EVENT_NORMAL_DUNGEON then InstanceID == 0 and applied to all instances for pair (map,diff)
|
||||
Difficulty difficulty :8; // used with mapid used as for select reset for global cooldown instances (instamceid==0 for event)
|
||||
uint16 mapid;
|
||||
uint32 instanceId; // used for select reset for normal dungeons
|
||||
|
||||
InstanceResetEvent() : type(RESET_EVENT_DUNGEON), difficulty(DUNGEON_DIFFICULTY_NORMAL), mapid(0), instanceId(0) {}
|
||||
InstanceResetEvent(ResetEventType t, uint32 _mapid, Difficulty d, uint32 _instanceid)
|
||||
DungeonResetEvent() : type(RESET_EVENT_NORMAL_DUNGEON), difficulty(DUNGEON_DIFFICULTY_NORMAL), mapid(0), instanceId(0) {}
|
||||
DungeonResetEvent(ResetEventType t, uint32 _mapid, Difficulty d, uint32 _instanceid)
|
||||
: type(t), difficulty(d), mapid(_mapid), instanceId(_instanceid) {}
|
||||
bool operator == (const InstanceResetEvent& e) { return e.mapid == mapid && e.difficulty == difficulty && e.instanceId == instanceId; }
|
||||
bool operator == (const DungeonResetEvent& e) { return e.mapid == mapid && e.difficulty == difficulty && e.instanceId == instanceId; }
|
||||
};
|
||||
|
||||
class InstanceResetScheduler
|
||||
class DungeonResetScheduler
|
||||
{
|
||||
public: // constructors
|
||||
explicit InstanceResetScheduler(InstanceSaveManager& mgr) : m_InstanceSaves(mgr) {}
|
||||
explicit DungeonResetScheduler(MapPersistentStateManager& mgr) : m_InstanceSaves(mgr) {}
|
||||
void LoadResetTimes();
|
||||
|
||||
public: // accessors
|
||||
|
|
@ -196,68 +245,73 @@ class InstanceResetScheduler
|
|||
m_resetTimeByMapDifficulty[MAKE_PAIR32(mapid,d)] = t;
|
||||
}
|
||||
|
||||
void ScheduleReset(bool add, time_t time, InstanceResetEvent event);
|
||||
void ScheduleReset(bool add, time_t time, DungeonResetEvent event);
|
||||
|
||||
void Update();
|
||||
|
||||
private: // fields
|
||||
InstanceSaveManager& m_InstanceSaves;
|
||||
MapPersistentStateManager& m_InstanceSaves;
|
||||
|
||||
|
||||
// fast lookup for reset times (always use existing functions for access/set)
|
||||
typedef UNORDERED_MAP<uint32 /*PAIR32(map,difficulty)*/,time_t /*resetTime*/> ResetTimeByMapDifficultyMap;
|
||||
ResetTimeByMapDifficultyMap m_resetTimeByMapDifficulty;
|
||||
|
||||
typedef std::multimap<time_t /*resetTime*/, InstanceResetEvent> ResetTimeQueue;
|
||||
typedef std::multimap<time_t /*resetTime*/, DungeonResetEvent> ResetTimeQueue;
|
||||
ResetTimeQueue m_resetTimeQueue;
|
||||
};
|
||||
|
||||
class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSaveManager, MaNGOS::ClassLevelLockable<InstanceSaveManager, ACE_Thread_Mutex> >
|
||||
class MANGOS_DLL_DECL MapPersistentStateManager : public MaNGOS::Singleton<MapPersistentStateManager, MaNGOS::ClassLevelLockable<MapPersistentStateManager, ACE_Thread_Mutex> >
|
||||
{
|
||||
friend class InstanceResetScheduler;
|
||||
public:
|
||||
InstanceSaveManager();
|
||||
~InstanceSaveManager();
|
||||
|
||||
void CleanupInstances();
|
||||
void PackInstances();
|
||||
friend class DungeonResetScheduler;
|
||||
public: // constructors
|
||||
MapPersistentStateManager();
|
||||
~MapPersistentStateManager();
|
||||
|
||||
public: // common for all MapPersistentState (sub)classes
|
||||
void LoadCreatureRespawnTimes();
|
||||
void LoadGameobjectRespawnTimes();
|
||||
|
||||
InstanceResetScheduler& GetScheduler() { return m_Scheduler; }
|
||||
// auto select appropriate MapPersistentState (sub)class by MapEntry, and autoselect appropriate way store (by instance/map id)
|
||||
// always return != NULL
|
||||
MapPersistentState* AddPersistentState(MapEntry const* mapEntry, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load = false);
|
||||
|
||||
// search stored state, can be NULL in result
|
||||
MapPersistentState *GetPersistentState(uint32 mapId, uint32 InstanceId);
|
||||
|
||||
void RemovePersistentState(uint32 mapId, uint32 instanceId);
|
||||
|
||||
public: // DungeonPersistentState specific
|
||||
void CleanupInstances();
|
||||
void PackInstances();
|
||||
|
||||
DungeonResetScheduler& GetScheduler() { return m_Scheduler; }
|
||||
|
||||
InstanceSave* AddInstanceSave(MapEntry const* mapEntry, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load = false);
|
||||
InstanceSave *GetInstanceSave(uint32 mapId, uint32 InstanceId);
|
||||
void RemoveInstanceSave(uint32 mapId, uint32 instanceId);
|
||||
static void DeleteInstanceFromDB(uint32 instanceid);
|
||||
|
||||
/* statistics */
|
||||
uint32 GetNumInstanceSaves() { return m_instanceSaveByInstanceId.size() + m_instanceSaveByMapId.size(); }
|
||||
uint32 GetNumBoundPlayersTotal();
|
||||
uint32 GetNumBoundGroupsTotal();
|
||||
void GetStatistics(uint32& numStates, uint32& numBoundPlayers, uint32& numBoundGroups);
|
||||
|
||||
void Update() { m_Scheduler.Update(); }
|
||||
private:
|
||||
typedef UNORDERED_MAP<uint32 /*InstanceId or MapId*/, InstanceSave*> InstanceSaveHashMap;
|
||||
typedef UNORDERED_MAP<uint32 /*InstanceId or MapId*/, MapPersistentState*> PersistentStateMap;
|
||||
|
||||
// called by scheduler
|
||||
void _ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeleft);
|
||||
void _ResetInstance(uint32 mapid, uint32 instanceId);
|
||||
void _CleanupExpiredInstancesAtTime(time_t t);
|
||||
|
||||
void _ResetSave(InstanceSaveHashMap& holder, InstanceSaveHashMap::iterator &itr);
|
||||
void _ResetSave(PersistentStateMap& holder, PersistentStateMap::iterator &itr);
|
||||
void _DelHelper(DatabaseType &db, const char *fields, const char *table, const char *queryTail,...);
|
||||
|
||||
// used during global instance resets
|
||||
bool lock_instLists;
|
||||
// fast lookup by instance id for instanceable maps
|
||||
InstanceSaveHashMap m_instanceSaveByInstanceId;
|
||||
PersistentStateMap m_instanceSaveByInstanceId;
|
||||
// fast lookup by map id for non-instanceable maps
|
||||
InstanceSaveHashMap m_instanceSaveByMapId;
|
||||
PersistentStateMap m_instanceSaveByMapId;
|
||||
|
||||
InstanceResetScheduler m_Scheduler;
|
||||
DungeonResetScheduler m_Scheduler;
|
||||
};
|
||||
|
||||
#define sInstanceSaveMgr MaNGOS::Singleton<InstanceSaveManager>::Instance()
|
||||
#define sMapPersistentStateMgr MaNGOS::Singleton<MapPersistentStateManager>::Instance()
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -553,7 +553,7 @@ bool ChatHandler::HandleGonameCommand(char* args)
|
|||
// if no bind exists, create a solo bind
|
||||
if (!gBind)
|
||||
{
|
||||
InstanceSave *save = target->GetMap()->GetInstanceSave();
|
||||
DungeonPersistentState *save = ((DungeonMap*)target->GetMap())->GetPersistanceState();
|
||||
|
||||
// if player is group leader then we need add group bind
|
||||
if (group && group->IsLeader(_player->GetObjectGuid()))
|
||||
|
|
|
|||
|
|
@ -6227,13 +6227,13 @@ bool ChatHandler::HandleInstanceListBindsCommand(char* /*args*/)
|
|||
Player::BoundInstancesMap &binds = player->GetBoundInstances(Difficulty(i));
|
||||
for(Player::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr)
|
||||
{
|
||||
InstanceSave *save = itr->second.save;
|
||||
std::string timeleft = secsToTimeString(save->GetResetTime() - time(NULL), true);
|
||||
DungeonPersistentState *state = itr->second.state;
|
||||
std::string timeleft = secsToTimeString(state->GetResetTime() - time(NULL), true);
|
||||
if (const MapEntry* entry = sMapStore.LookupEntry(itr->first))
|
||||
{
|
||||
PSendSysMessage("map: %d (%s) inst: %d perm: %s diff: %d canReset: %s TTR: %s",
|
||||
itr->first, entry->name[GetSessionDbcLocale()], save->GetInstanceId(), itr->second.perm ? "yes" : "no",
|
||||
save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str());
|
||||
itr->first, entry->name[GetSessionDbcLocale()], state->GetInstanceId(), itr->second.perm ? "yes" : "no",
|
||||
state->GetDifficulty(), state->CanReset() ? "yes" : "no", timeleft.c_str());
|
||||
}
|
||||
else
|
||||
PSendSysMessage("bound for a nonexistent map %u", itr->first);
|
||||
|
|
@ -6242,21 +6242,21 @@ bool ChatHandler::HandleInstanceListBindsCommand(char* /*args*/)
|
|||
}
|
||||
PSendSysMessage("player binds: %d", counter);
|
||||
counter = 0;
|
||||
Group *group = player->GetGroup();
|
||||
if(group)
|
||||
|
||||
if (Group *group = player->GetGroup())
|
||||
{
|
||||
for(uint8 i = 0; i < MAX_DIFFICULTY; ++i)
|
||||
{
|
||||
Group::BoundInstancesMap &binds = group->GetBoundInstances(Difficulty(i));
|
||||
for(Group::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr)
|
||||
{
|
||||
InstanceSave *save = itr->second.save;
|
||||
std::string timeleft = secsToTimeString(save->GetResetTime() - time(NULL), true);
|
||||
DungeonPersistentState *state = itr->second.state;
|
||||
std::string timeleft = secsToTimeString(state->GetResetTime() - time(NULL), true);
|
||||
if (const MapEntry* entry = sMapStore.LookupEntry(itr->first))
|
||||
{
|
||||
PSendSysMessage("map: %d (%s) inst: %d perm: %s diff: %d canReset: %s TTR: %s",
|
||||
itr->first, entry->name[GetSessionDbcLocale()], save->GetInstanceId(), itr->second.perm ? "yes" : "no",
|
||||
save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str());
|
||||
itr->first, entry->name[GetSessionDbcLocale()], state->GetInstanceId(), itr->second.perm ? "yes" : "no",
|
||||
state->GetDifficulty(), state->CanReset() ? "yes" : "no", timeleft.c_str());
|
||||
}
|
||||
else
|
||||
PSendSysMessage("bound for a nonexistent map %u", itr->first);
|
||||
|
|
@ -6302,7 +6302,7 @@ bool ChatHandler::HandleInstanceUnbindCommand(char* args)
|
|||
}
|
||||
if(itr->first != player->GetMapId())
|
||||
{
|
||||
InstanceSave *save = itr->second.save;
|
||||
DungeonPersistentState *save = itr->second.state;
|
||||
std::string timeleft = secsToTimeString(save->GetResetTime() - time(NULL), true);
|
||||
|
||||
if (const MapEntry* entry = sMapStore.LookupEntry(itr->first))
|
||||
|
|
@ -6328,9 +6328,12 @@ bool ChatHandler::HandleInstanceStatsCommand(char* /*args*/)
|
|||
{
|
||||
PSendSysMessage("instances loaded: %d", sMapMgr.GetNumInstances());
|
||||
PSendSysMessage("players in instances: %d", sMapMgr.GetNumPlayersInInstances());
|
||||
PSendSysMessage("instance saves: %d", sInstanceSaveMgr.GetNumInstanceSaves());
|
||||
PSendSysMessage("players bound: %d", sInstanceSaveMgr.GetNumBoundPlayersTotal());
|
||||
PSendSysMessage("groups bound: %d", sInstanceSaveMgr.GetNumBoundGroupsTotal());
|
||||
|
||||
uint32 numSaves, numBoundPlayers, numBoundGroups;
|
||||
sMapPersistentStateMgr.GetStatistics(numSaves, numBoundPlayers, numBoundGroups);
|
||||
PSendSysMessage("instance saves: %d", numSaves);
|
||||
PSendSysMessage("players bound: %d", numBoundPlayers);
|
||||
PSendSysMessage("groups bound: %d", numBoundGroups);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
149
src/game/Map.cpp
149
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,24 +1372,21 @@ 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)
|
||||
{
|
||||
// cannot enter other instances if bound permanently
|
||||
if (playerBind->save != GetInstanceSave())
|
||||
if (playerBind->state != GetPersistanceState())
|
||||
{
|
||||
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());
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1400,18 +1399,18 @@ bool InstanceMap::Add(Player *player)
|
|||
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());
|
||||
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("InstanceMap::Add: the group (Id: %d) is bound to instance %d,%d,%d,%d,%d,%d",
|
||||
sLog.outError("DungeonMap::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());
|
||||
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());
|
||||
|
|
@ -1419,23 +1418,23 @@ bool InstanceMap::Add(Player *player)
|
|||
|
||||
// bind to the group or keep using the group save
|
||||
if (!groupBind)
|
||||
pGroup->BindToInstance(GetInstanceSave(), false);
|
||||
pGroup->BindToInstance(GetPersistanceState(), false);
|
||||
else
|
||||
{
|
||||
// cannot jump to a different instance without resetting it
|
||||
if (groupBind->save != GetInstanceSave())
|
||||
if (groupBind->state != GetPersistentState())
|
||||
{
|
||||
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("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",
|
||||
GetInstanceSave()->GetPlayerCount(), GetInstanceSave()->GetGroupCount());
|
||||
GetPersistanceState()->GetPlayerCount(), GetPersistanceState()->GetGroupCount());
|
||||
|
||||
if (groupBind->save)
|
||||
sLog.outError("GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->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);
|
||||
|
|
@ -1447,7 +1446,7 @@ bool InstanceMap::Add(Player *player)
|
|||
WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
|
||||
data << uint32(0);
|
||||
player->GetSession()->SendPacket(&data);
|
||||
player->BindToInstance(GetInstanceSave(), true);
|
||||
player->BindToInstance(GetPersistanceState(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1455,11 +1454,10 @@ bool InstanceMap::Add(Player *player)
|
|||
{
|
||||
// set up a solo bind or continue using it
|
||||
if(!playerBind)
|
||||
player->BindToInstance(GetInstanceSave(), false);
|
||||
player->BindToInstance(GetPersistanceState(), false);
|
||||
else
|
||||
// cannot jump to a different instance without resetting it
|
||||
MANGOS_ASSERT(playerBind->save == GetInstanceSave());
|
||||
}
|
||||
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
|
||||
|
|
|
|||
|
|
@ -45,7 +45,9 @@ class Unit;
|
|||
class WorldPacket;
|
||||
class InstanceData;
|
||||
class Group;
|
||||
class InstanceSave;
|
||||
class MapPersistentState;
|
||||
class DungeonPersistentState;
|
||||
class BattleGroundPersistentState;
|
||||
struct ScriptInfo;
|
||||
class BattleGround;
|
||||
class GridMap;
|
||||
|
|
@ -188,7 +190,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>
|
|||
bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); }
|
||||
|
||||
// can't be NULL for loaded map
|
||||
InstanceSave* GetInstanceSave() const { return m_instanceSave; }
|
||||
MapPersistentState* GetPersistentState() const { return m_persistentState; }
|
||||
|
||||
void AddObjectToRemoveList(WorldObject *obj);
|
||||
|
||||
|
|
@ -295,7 +297,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>
|
|||
uint32 i_InstanceId;
|
||||
uint32 m_unloadTimer;
|
||||
float m_VisibleDistance;
|
||||
InstanceSave* m_instanceSave;
|
||||
MapPersistentState* m_persistentState;
|
||||
|
||||
MapRefManager m_mapRefManager;
|
||||
MapRefManager::iterator m_mapRefIter;
|
||||
|
|
@ -337,11 +339,13 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>
|
|||
void RemoveFromGrid(T*, NGridType *, Cell const&);
|
||||
};
|
||||
|
||||
class MANGOS_DLL_SPEC InstanceMap : public Map
|
||||
class MANGOS_DLL_SPEC DungeonMap : public Map
|
||||
{
|
||||
private:
|
||||
using Map::GetPersistentState; // hide in subclass for overwrite
|
||||
public:
|
||||
InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode);
|
||||
~InstanceMap();
|
||||
DungeonMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode);
|
||||
~DungeonMap();
|
||||
bool Add(Player *);
|
||||
void Remove(Player *, bool);
|
||||
void Update(const uint32&);
|
||||
|
|
@ -352,6 +356,9 @@ class MANGOS_DLL_SPEC InstanceMap : public Map
|
|||
void SendResetWarnings(uint32 timeLeft) const;
|
||||
void SetResetSchedule(bool on);
|
||||
|
||||
// can't be NULL for loaded map
|
||||
DungeonPersistentState* GetPersistanceState() const;
|
||||
|
||||
virtual void InitVisibilityDistance();
|
||||
private:
|
||||
bool m_resetAfterUnload;
|
||||
|
|
@ -360,6 +367,8 @@ class MANGOS_DLL_SPEC InstanceMap : public Map
|
|||
|
||||
class MANGOS_DLL_SPEC BattleGroundMap : public Map
|
||||
{
|
||||
private:
|
||||
using Map::GetPersistentState; // hide in subclass for overwrite
|
||||
public:
|
||||
BattleGroundMap(uint32 id, time_t, uint32 InstanceId, uint8 spawnMode);
|
||||
~BattleGroundMap();
|
||||
|
|
@ -374,6 +383,10 @@ class MANGOS_DLL_SPEC BattleGroundMap : public Map
|
|||
virtual void InitVisibilityDistance();
|
||||
BattleGround* GetBG() { return m_bg; }
|
||||
void SetBG(BattleGround* bg) { m_bg = bg; }
|
||||
|
||||
// can't be NULL for loaded map
|
||||
BattleGroundPersistentState* GetPersistanceState() const;
|
||||
|
||||
private:
|
||||
BattleGround* m_bg;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ Map* MapManager::CreateMap(uint32 id, const WorldObject* obj)
|
|||
if(entry->Instanceable())
|
||||
{
|
||||
MANGOS_ASSERT(obj->GetTypeId() == TYPEID_PLAYER);
|
||||
//create InstanceMap object
|
||||
//create DungeonMap object
|
||||
if(obj->GetTypeId() == TYPEID_PLAYER)
|
||||
m = CreateInstance(id, (Player*)obj);
|
||||
}
|
||||
|
|
@ -370,14 +370,14 @@ Map* MapManager::CreateInstance(uint32 id, Player * player)
|
|||
map = FindMap(id, NewInstanceId);
|
||||
MANGOS_ASSERT(map);
|
||||
}
|
||||
else if (InstanceSave* pSave = player->GetBoundInstanceSaveForSelfOrGroup(id))
|
||||
else if (DungeonPersistentState* pSave = player->GetBoundInstanceSaveForSelfOrGroup(id))
|
||||
{
|
||||
// solo/perm/group
|
||||
NewInstanceId = pSave->GetInstanceId();
|
||||
map = FindMap(id, NewInstanceId);
|
||||
// it is possible that the save exists but the map doesn't
|
||||
if (!map)
|
||||
pNewMap = CreateInstanceMap(id, NewInstanceId, pSave->GetDifficulty(), pSave);
|
||||
pNewMap = CreateDungeonMap(id, NewInstanceId, pSave->GetDifficulty(), pSave);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -386,7 +386,7 @@ Map* MapManager::CreateInstance(uint32 id, Player * player)
|
|||
NewInstanceId = sObjectMgr.GenerateLowGuid(HIGHGUID_INSTANCE);
|
||||
|
||||
Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficulty(entry->IsRaid()) : player->GetDifficulty(entry->IsRaid());
|
||||
pNewMap = CreateInstanceMap(id, NewInstanceId, diff);
|
||||
pNewMap = CreateDungeonMap(id, NewInstanceId, diff);
|
||||
}
|
||||
|
||||
//add a new map object into the registry
|
||||
|
|
@ -399,17 +399,17 @@ Map* MapManager::CreateInstance(uint32 id, Player * player)
|
|||
return map;
|
||||
}
|
||||
|
||||
InstanceMap* MapManager::CreateInstanceMap(uint32 id, uint32 InstanceId, Difficulty difficulty, InstanceSave *save)
|
||||
DungeonMap* MapManager::CreateDungeonMap(uint32 id, uint32 InstanceId, Difficulty difficulty, DungeonPersistentState *save)
|
||||
{
|
||||
// make sure we have a valid map id
|
||||
if (!sMapStore.LookupEntry(id))
|
||||
{
|
||||
sLog.outError("CreateInstanceMap: no entry for map %d", id);
|
||||
sLog.outError("CreateDungeonMap: no entry for map %d", id);
|
||||
MANGOS_ASSERT(false);
|
||||
}
|
||||
if (!ObjectMgr::GetInstanceTemplate(id))
|
||||
{
|
||||
sLog.outError("CreateInstanceMap: no instance template for map %d", id);
|
||||
sLog.outError("CreateDungeonMap: no instance template for map %d", id);
|
||||
MANGOS_ASSERT(false);
|
||||
}
|
||||
|
||||
|
|
@ -417,10 +417,9 @@ InstanceMap* MapManager::CreateInstanceMap(uint32 id, uint32 InstanceId, Difficu
|
|||
if (!GetMapDifficultyData(id, difficulty))
|
||||
difficulty = DUNGEON_DIFFICULTY_NORMAL;
|
||||
|
||||
DEBUG_LOG("MapInstanced::CreateInstanceMap: %s map instance %d for %d created with difficulty %d", save?"":"new ", InstanceId, id, difficulty);
|
||||
DEBUG_LOG("MapInstanced::CreateDungeonMap: %s map instance %d for %d created with difficulty %d", save?"":"new ", InstanceId, id, difficulty);
|
||||
|
||||
InstanceMap *map = new InstanceMap(id, i_gridCleanUpDelay, InstanceId, difficulty);
|
||||
MANGOS_ASSERT(map->IsDungeon());
|
||||
DungeonMap *map = new DungeonMap(id, i_gridCleanUpDelay, InstanceId, difficulty);
|
||||
|
||||
// Dungeons can have saved instance data
|
||||
bool load_data = save != NULL;
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::
|
|||
void DeleteStateMachine();
|
||||
|
||||
Map* CreateInstance(uint32 id, Player * player);
|
||||
InstanceMap* CreateInstanceMap(uint32 id, uint32 InstanceId, Difficulty difficulty, InstanceSave *save = NULL);
|
||||
DungeonMap* CreateDungeonMap(uint32 id, uint32 InstanceId, Difficulty difficulty, DungeonPersistentState *save = NULL);
|
||||
BattleGroundMap* CreateBattleGroundMap(uint32 id, uint32 InstanceId, BattleGround* bg);
|
||||
|
||||
uint32 i_gridCleanUpDelay;
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ void WorldSession::HandleMoveWorldportAckOpcode()
|
|||
{
|
||||
if (mapDiff->resetTime)
|
||||
{
|
||||
if (time_t timeReset = sInstanceSaveMgr.GetScheduler().GetResetTimeFor(mEntry->MapID,diff))
|
||||
if (time_t timeReset = sMapPersistentStateMgr.GetScheduler().GetResetTimeFor(mEntry->MapID,diff))
|
||||
{
|
||||
uint32 timeleft = uint32(timeReset - time(NULL));
|
||||
GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft);
|
||||
|
|
|
|||
|
|
@ -3621,8 +3621,8 @@ void ObjectMgr::LoadGroups()
|
|||
diff = REGULAR_DIFFICULTY; // default for both difficaly types
|
||||
}
|
||||
|
||||
InstanceSave *save = sInstanceSaveMgr.AddInstanceSave(mapEntry, fields[2].GetUInt32(), Difficulty(diff), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true);
|
||||
group->BindToInstance(save, fields[3].GetBool(), true);
|
||||
DungeonPersistentState *state = (DungeonPersistentState*)sMapPersistentStateMgr.AddPersistentState(mapEntry, fields[2].GetUInt32(), Difficulty(diff), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true);
|
||||
group->BindToInstance(state, fields[3].GetBool(), true);
|
||||
}while( result->NextRow() );
|
||||
delete result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -624,7 +624,7 @@ Player::~Player ()
|
|||
// clean up player-instance binds, may unload some instance saves
|
||||
for(uint8 i = 0; i < MAX_DIFFICULTY; ++i)
|
||||
for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
|
||||
itr->second.save->RemovePlayer(this);
|
||||
itr->second.state->RemovePlayer(this);
|
||||
|
||||
delete m_declinedname;
|
||||
delete m_runes;
|
||||
|
|
@ -15453,13 +15453,13 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder *holder )
|
|||
}
|
||||
|
||||
// player bounded instance saves loaded in _LoadBoundInstances, group versions at group loading
|
||||
InstanceSave* instanceSave = GetBoundInstanceSaveForSelfOrGroup(GetMapId());
|
||||
DungeonPersistentState* state = 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() && !instanceSave)
|
||||
if(GetInstanceId() && !state)
|
||||
{
|
||||
AreaTrigger const* at = sObjectMgr.GetMapEntranceTrigger(GetMapId());
|
||||
if(at)
|
||||
|
|
@ -16681,8 +16681,8 @@ void Player::_LoadBoundInstances(QueryResult *result)
|
|||
}
|
||||
|
||||
// since non permanent binds are always solo bind, they can always be reset
|
||||
InstanceSave *save = sInstanceSaveMgr.AddInstanceSave(mapEntry, instanceId, Difficulty(difficulty), resetTime, !perm, true);
|
||||
if(save) BindToInstance(save, perm, true);
|
||||
DungeonPersistentState *state = (DungeonPersistentState*)sMapPersistentStateMgr.AddPersistentState(mapEntry, instanceId, Difficulty(difficulty), resetTime, !perm, true);
|
||||
if(state) BindToInstance(state, perm, true);
|
||||
} while(result->NextRow());
|
||||
delete result;
|
||||
}
|
||||
|
|
@ -16712,65 +16712,76 @@ void Player::UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficu
|
|||
{
|
||||
if(itr != m_boundInstances[difficulty].end())
|
||||
{
|
||||
if(!unload) CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%u' AND instance = '%u'", GetGUIDLow(), itr->second.save->GetInstanceId());
|
||||
itr->second.save->RemovePlayer(this); // save can become invalid
|
||||
if (!unload)
|
||||
CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%u' AND instance = '%u'",
|
||||
GetGUIDLow(), itr->second.state->GetInstanceId());
|
||||
itr->second.state->RemovePlayer(this); // state can become invalid
|
||||
m_boundInstances[difficulty].erase(itr++);
|
||||
}
|
||||
}
|
||||
|
||||
InstancePlayerBind* Player::BindToInstance(InstanceSave *save, bool permanent, bool load)
|
||||
InstancePlayerBind* Player::BindToInstance(DungeonPersistentState *state, bool permanent, bool load)
|
||||
{
|
||||
if(save)
|
||||
if (state)
|
||||
{
|
||||
InstancePlayerBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()];
|
||||
if(bind.save)
|
||||
InstancePlayerBind& bind = m_boundInstances[state->GetDifficulty()][state->GetMapId()];
|
||||
if (bind.state)
|
||||
{
|
||||
// update the save when the group kills a boss
|
||||
if(permanent != bind.perm || save != bind.save)
|
||||
if(!load) CharacterDatabase.PExecute("UPDATE character_instance SET instance = '%u', permanent = '%u' WHERE guid = '%u' AND instance = '%u'", save->GetInstanceId(), permanent, GetGUIDLow(), bind.save->GetInstanceId());
|
||||
// update the state when the group kills a boss
|
||||
if(permanent != bind.perm || state != bind.state)
|
||||
if (!load)
|
||||
CharacterDatabase.PExecute("UPDATE character_instance SET instance = '%u', permanent = '%u' WHERE guid = '%u' AND instance = '%u'",
|
||||
state->GetInstanceId(), permanent, GetGUIDLow(), bind.state->GetInstanceId());
|
||||
}
|
||||
else
|
||||
if(!load) CharacterDatabase.PExecute("INSERT INTO character_instance (guid, instance, permanent) VALUES ('%u', '%u', '%u')", GetGUIDLow(), save->GetInstanceId(), permanent);
|
||||
|
||||
if(bind.save != save)
|
||||
{
|
||||
if(bind.save)
|
||||
bind.save->RemovePlayer(this);
|
||||
save->AddPlayer(this);
|
||||
if (!load)
|
||||
CharacterDatabase.PExecute("INSERT INTO character_instance (guid, instance, permanent) VALUES ('%u', '%u', '%u')",
|
||||
GetGUIDLow(), state->GetInstanceId(), permanent);
|
||||
}
|
||||
|
||||
if(permanent) save->SetCanReset(false);
|
||||
if (bind.state != state)
|
||||
{
|
||||
if (bind.state)
|
||||
bind.state->RemovePlayer(this);
|
||||
state->AddPlayer(this);
|
||||
}
|
||||
|
||||
bind.save = save;
|
||||
if (permanent)
|
||||
state->SetCanReset(false);
|
||||
|
||||
bind.state = state;
|
||||
bind.perm = permanent;
|
||||
if(!load) DEBUG_LOG("Player::BindToInstance: %s(%d) is now bound to map %d, instance %d, difficulty %d", GetName(), GetGUIDLow(), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty());
|
||||
if (!load)
|
||||
DEBUG_LOG("Player::BindToInstance: %s(%d) is now bound to map %d, instance %d, difficulty %d",
|
||||
GetName(), GetGUIDLow(), state->GetMapId(), state->GetInstanceId(), state->GetDifficulty());
|
||||
return &bind;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InstanceSave* Player::GetBoundInstanceSaveForSelfOrGroup(uint32 mapid)
|
||||
DungeonPersistentState* Player::GetBoundInstanceSaveForSelfOrGroup(uint32 mapid)
|
||||
{
|
||||
MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
|
||||
if(!mapEntry)
|
||||
if (!mapEntry)
|
||||
return NULL;
|
||||
|
||||
InstancePlayerBind *pBind = GetBoundInstance(mapid, GetDifficulty(mapEntry->IsRaid()));
|
||||
InstanceSave *pSave = pBind ? pBind->save : NULL;
|
||||
DungeonPersistentState *state = pBind ? pBind->state : NULL;
|
||||
|
||||
// the player's permanent player bind is taken into consideration first
|
||||
// then the player's group bind and finally the solo bind.
|
||||
if(!pBind || !pBind->perm)
|
||||
if (!pBind || !pBind->perm)
|
||||
{
|
||||
InstanceGroupBind *groupBind = NULL;
|
||||
Group *group = GetGroup();
|
||||
// use the player's difficulty setting (it may not be the same as the group's)
|
||||
if(group && (groupBind = group->GetBoundInstance(mapid, this)))
|
||||
pSave = groupBind->save;
|
||||
if (Group *group = GetGroup())
|
||||
if (groupBind = group->GetBoundInstance(mapid, this))
|
||||
state = groupBind->state;
|
||||
}
|
||||
|
||||
return pSave;
|
||||
return state;
|
||||
}
|
||||
|
||||
void Player::SendRaidInfo()
|
||||
|
|
@ -16788,15 +16799,15 @@ void Player::SendRaidInfo()
|
|||
{
|
||||
for (BoundInstancesMap::const_iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
|
||||
{
|
||||
if(itr->second.perm)
|
||||
if (itr->second.perm)
|
||||
{
|
||||
InstanceSave *save = itr->second.save;
|
||||
data << uint32(save->GetMapId()); // map id
|
||||
data << uint32(save->GetDifficulty()); // difficulty
|
||||
data << ObjectGuid(save->GetInstanceGuid());// instance guid
|
||||
DungeonPersistentState *state = itr->second.state;
|
||||
data << uint32(state->GetMapId()); // map id
|
||||
data << uint32(state->GetDifficulty()); // difficulty
|
||||
data << ObjectGuid(state->GetInstanceGuid());// instance guid
|
||||
data << uint8(1); // expired = 0
|
||||
data << uint8(0); // extended = 1
|
||||
data << uint32(save->GetResetTime() - now); // reset time
|
||||
data << uint32(state->GetResetTime() - now);// reset time
|
||||
++counter;
|
||||
}
|
||||
}
|
||||
|
|
@ -16840,7 +16851,7 @@ void Player::SendSavedInstances()
|
|||
if(itr->second.perm)
|
||||
{
|
||||
data.Initialize(SMSG_UPDATE_LAST_INSTANCE);
|
||||
data << uint32(itr->second.save->GetMapId());
|
||||
data << uint32(itr->second.state->GetMapId());
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
|
|
@ -16865,16 +16876,19 @@ void Player::ConvertInstancesToGroup(Player *player, Group *group, ObjectGuid pl
|
|||
// copy all binds to the group, when changing leader it's assumed the character
|
||||
// will not have any solo binds
|
||||
|
||||
if(player)
|
||||
if (player)
|
||||
{
|
||||
for(uint8 i = 0; i < MAX_DIFFICULTY; ++i)
|
||||
{
|
||||
for (BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();)
|
||||
{
|
||||
has_binds = true;
|
||||
if(group) group->BindToInstance(itr->second.save, itr->second.perm, true);
|
||||
|
||||
if (group)
|
||||
group->BindToInstance(itr->second.state, itr->second.perm, true);
|
||||
|
||||
// permanent binds are not removed
|
||||
if(!itr->second.perm)
|
||||
if (!itr->second.perm)
|
||||
{
|
||||
// increments itr in call
|
||||
player->UnbindInstance(itr, Difficulty(i), true);
|
||||
|
|
@ -16889,11 +16903,11 @@ void Player::ConvertInstancesToGroup(Player *player, Group *group, ObjectGuid pl
|
|||
uint32 player_lowguid = player_guid.GetCounter();
|
||||
|
||||
// if the player's not online we don't know what binds it has
|
||||
if(!player || !group || has_binds)
|
||||
if (!player || !group || has_binds)
|
||||
CharacterDatabase.PExecute("INSERT INTO group_instance SELECT guid, instance, permanent FROM character_instance WHERE guid = '%u'", player_lowguid);
|
||||
|
||||
// the following should not get executed when changing leaders
|
||||
if(!player || has_solo)
|
||||
if (!player || has_solo)
|
||||
CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%u' AND permanent = 0", player_lowguid);
|
||||
}
|
||||
|
||||
|
|
@ -17777,18 +17791,18 @@ void Player::ResetInstances(InstanceResetMethod method, bool isRaid)
|
|||
|
||||
for (BoundInstancesMap::iterator itr = m_boundInstances[diff].begin(); itr != m_boundInstances[diff].end();)
|
||||
{
|
||||
InstanceSave *p = itr->second.save;
|
||||
DungeonPersistentState *state = itr->second.state;
|
||||
const MapEntry *entry = sMapStore.LookupEntry(itr->first);
|
||||
if(!entry || entry->IsRaid() != isRaid || !p->CanReset())
|
||||
if (!entry || entry->IsRaid() != isRaid || !state->CanReset())
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(method == INSTANCE_RESET_ALL)
|
||||
if (method == INSTANCE_RESET_ALL)
|
||||
{
|
||||
// the "reset all instances" method can only reset normal maps
|
||||
if(entry->map_type == MAP_RAID || diff == DUNGEON_DIFFICULTY_HEROIC)
|
||||
if (entry->map_type == MAP_RAID || diff == DUNGEON_DIFFICULTY_HEROIC)
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
|
|
@ -17796,19 +17810,19 @@ void Player::ResetInstances(InstanceResetMethod method, bool isRaid)
|
|||
}
|
||||
|
||||
// if the map is loaded, reset it
|
||||
Map *map = sMapMgr.FindMap(p->GetMapId(), p->GetInstanceId());
|
||||
if(map && map->IsDungeon())
|
||||
((InstanceMap*)map)->Reset(method);
|
||||
if (Map *map = sMapMgr.FindMap(state->GetMapId(), state->GetInstanceId()))
|
||||
if (map->IsDungeon())
|
||||
((DungeonMap*)map)->Reset(method);
|
||||
|
||||
// since this is a solo instance there should not be any players inside
|
||||
if(method == INSTANCE_RESET_ALL || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
|
||||
SendResetInstanceSuccess(p->GetMapId());
|
||||
if (method == INSTANCE_RESET_ALL || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
|
||||
SendResetInstanceSuccess(state->GetMapId());
|
||||
|
||||
p->DeleteFromDB();
|
||||
state->DeleteFromDB();
|
||||
m_boundInstances[diff].erase(itr++);
|
||||
|
||||
// the following should remove the instance save from the manager and delete it as well
|
||||
p->RemovePlayer(this);
|
||||
state->RemovePlayer(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class UpdateMask;
|
|||
class SpellCastTargets;
|
||||
class PlayerSocial;
|
||||
class Vehicle;
|
||||
class InstanceSave;
|
||||
class DungeonPersistentState;
|
||||
class Spell;
|
||||
class Item;
|
||||
|
||||
|
|
@ -945,12 +945,12 @@ enum ReputationSource
|
|||
|
||||
struct InstancePlayerBind
|
||||
{
|
||||
InstanceSave *save;
|
||||
DungeonPersistentState *state;
|
||||
bool perm;
|
||||
/* permanent PlayerInstanceBinds are created in Raid/Heroic instances for players
|
||||
that aren't already permanently bound when they are inside when a boss is killed
|
||||
or when they enter an instance that the group leader is permanently bound to. */
|
||||
InstancePlayerBind() : save(NULL), perm(false) {}
|
||||
InstancePlayerBind() : state(NULL), perm(false) {}
|
||||
};
|
||||
|
||||
class MANGOS_DLL_SPEC PlayerTaxi
|
||||
|
|
@ -2330,11 +2330,11 @@ class MANGOS_DLL_SPEC Player : public Unit
|
|||
BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; }
|
||||
void UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload = false);
|
||||
void UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload = false);
|
||||
InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false);
|
||||
InstancePlayerBind* BindToInstance(DungeonPersistentState *save, bool permanent, bool load = false);
|
||||
void SendRaidInfo();
|
||||
void SendSavedInstances();
|
||||
static void ConvertInstancesToGroup(Player *player, Group *group = NULL, ObjectGuid player_guid = ObjectGuid());
|
||||
InstanceSave* GetBoundInstanceSaveForSelfOrGroup(uint32 mapid);
|
||||
DungeonPersistentState* GetBoundInstanceSaveForSelfOrGroup(uint32 mapid);
|
||||
|
||||
/*********************************************************/
|
||||
/*** GROUP SYSTEM ***/
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ void PoolGroup<Creature>::Spawn1Object(PoolObject* obj, bool instantly)
|
|||
// for not loaded grid just update respawn time (avoid work for instances until implemented support)
|
||||
else if(!instantly)
|
||||
{
|
||||
map->GetInstanceSave()->SaveCreatureRespawnTime(obj->guid, time(NULL) + data->spawntimesecs);
|
||||
map->GetPersistentState()->SaveCreatureRespawnTime(obj->guid, time(NULL) + data->spawntimesecs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -453,7 +453,7 @@ void PoolGroup<GameObject>::Spawn1Object(PoolObject* obj, bool instantly)
|
|||
{
|
||||
// for spawned by default object only
|
||||
if (data->spawntimesecs >= 0)
|
||||
map->GetInstanceSave()->SaveGORespawnTime(obj->guid, time(NULL) + data->spawntimesecs);
|
||||
map->GetPersistentState()->SaveGORespawnTime(obj->guid, time(NULL) + data->spawntimesecs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -875,15 +875,16 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
|
|||
if (m->IsRaidOrHeroicDungeon())
|
||||
{
|
||||
if(cVictim->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
|
||||
((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer);
|
||||
((DungeonMap *)m)->PermBindAllPlayers(creditedPlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
DungeonPersistentState* save = ((DungeonMap*)m)->GetPersistanceState();
|
||||
// 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 (m->GetInstanceSave()->GetResetTime() < resettime)
|
||||
m->GetInstanceSave()->SetResetTime(resettime);
|
||||
if (save->GetResetTime() < resettime)
|
||||
save->SetResetTime(resettime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -942,10 +942,10 @@ void World::SetInitialWorldSettings()
|
|||
|
||||
///- Clean up and pack instances
|
||||
sLog.outString( "Cleaning up instances..." );
|
||||
sInstanceSaveMgr.CleanupInstances(); // must be called before `creature_respawn`/`gameobject_respawn` tables
|
||||
sMapPersistentStateMgr.CleanupInstances(); // must be called before `creature_respawn`/`gameobject_respawn` tables
|
||||
|
||||
sLog.outString( "Packing instances..." );
|
||||
sInstanceSaveMgr.PackInstances();
|
||||
sMapPersistentStateMgr.PackInstances();
|
||||
|
||||
sLog.outString( "Packing groups..." );
|
||||
sObjectMgr.PackGroupIds(); // must be after CleanupInstances
|
||||
|
|
@ -1042,13 +1042,13 @@ void World::SetInitialWorldSettings()
|
|||
sLog.outString();
|
||||
|
||||
sLog.outString( "Loading Creature Respawn Data..." ); // must be after PackInstances()
|
||||
sInstanceSaveMgr.LoadCreatureRespawnTimes();
|
||||
sMapPersistentStateMgr.LoadCreatureRespawnTimes();
|
||||
|
||||
sLog.outString( "Loading Gameobject Data..." );
|
||||
sObjectMgr.LoadGameobjects();
|
||||
|
||||
sLog.outString( "Loading Gameobject Respawn Data..." ); // must be after PackInstances()
|
||||
sInstanceSaveMgr.LoadGameobjectRespawnTimes();
|
||||
sMapPersistentStateMgr.LoadGameobjectRespawnTimes();
|
||||
|
||||
sLog.outString( "Loading Objects Pooling Data...");
|
||||
sPoolMgr.LoadFromDB();
|
||||
|
|
@ -1524,7 +1524,7 @@ void World::Update(uint32 diff)
|
|||
sMapMgr.RemoveAllObjectsInRemoveList();
|
||||
|
||||
// update the instance reset times
|
||||
sInstanceSaveMgr.Update();
|
||||
sMapPersistentStateMgr.Update();
|
||||
|
||||
// And last, but not least handle the issued cli commands
|
||||
ProcessCliCommands();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "11125"
|
||||
#define REVISION_NR "11126"
|
||||
#endif // __REVISION_NR_H__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue