[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:
VladimirMangos 2011-02-10 03:55:45 +03:00
parent 0d16b0bdc7
commit dde16bc48c
22 changed files with 683 additions and 550 deletions

View file

@ -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);
}
}