mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 13:37:05 +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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue