cleanup fixes of solo dungeon queue
This commit is contained in:
1 parent
f35c3c4ae9
commit
1a9cd340b7
9 files changed
+188
-8
No files matched your search
@@ -22,7 +22,8 @@ namespace lfg
|
||||
{
|
||||
|
||||
LfgGroupData::LfgGroupData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE),
|
||||
m_Leader(), m_Dungeon(0), m_KicksLeft(LFG_GROUP_MAX_KICKS), m_VoteKickActive(false)
|
||||
m_Leader(), m_Dungeon(0), m_LowPopulation(false), m_LowPopulationOutsideSince(0),
|
||||
m_KicksLeft(LFG_GROUP_MAX_KICKS), m_VoteKickActive(false)
|
||||
{ }
|
||||
|
||||
LfgGroupData::~LfgGroupData()
|
||||
@@ -83,6 +84,34 @@ void LfgGroupData::SetDungeon(uint32 dungeon)
|
||||
m_Dungeon = dungeon;
|
||||
}
|
||||
|
||||
// LOWPOP_GROUP_LIFECYCLE
|
||||
void LfgGroupData::SetLowPopulation(bool enabled)
|
||||
{
|
||||
m_LowPopulation = enabled;
|
||||
if (!enabled)
|
||||
m_LowPopulationOutsideSince = 0;
|
||||
}
|
||||
|
||||
bool LfgGroupData::IsLowPopulation() const
|
||||
{
|
||||
return m_LowPopulation;
|
||||
}
|
||||
|
||||
void LfgGroupData::SetLowPopulationOutsideSince(time_t timestamp)
|
||||
{
|
||||
m_LowPopulationOutsideSince = timestamp;
|
||||
}
|
||||
|
||||
time_t LfgGroupData::GetLowPopulationOutsideSince() const
|
||||
{
|
||||
return m_LowPopulationOutsideSince;
|
||||
}
|
||||
|
||||
void LfgGroupData::ClearLowPopulationOutsideSince()
|
||||
{
|
||||
m_LowPopulationOutsideSince = 0;
|
||||
}
|
||||
|
||||
void LfgGroupData::DecreaseKicksLeft()
|
||||
{
|
||||
if (m_KicksLeft)
|
||||
|
||||
@@ -50,6 +50,13 @@ class TC_GAME_API LfgGroupData
|
||||
// Dungeon
|
||||
void SetDungeon(uint32 dungeon);
|
||||
|
||||
// Low-population dungeon groups
|
||||
void SetLowPopulation(bool enabled);
|
||||
bool IsLowPopulation() const;
|
||||
void SetLowPopulationOutsideSince(time_t timestamp);
|
||||
time_t GetLowPopulationOutsideSince() const;
|
||||
void ClearLowPopulationOutsideSince();
|
||||
|
||||
// VoteKick
|
||||
void DecreaseKicksLeft();
|
||||
|
||||
@@ -77,6 +84,9 @@ class TC_GAME_API LfgGroupData
|
||||
GuidSet m_Players; ///< Players in group
|
||||
// Dungeon
|
||||
uint32 m_Dungeon; ///< Dungeon entry
|
||||
// Low-population dungeon group
|
||||
bool m_LowPopulation; ///< Group was started below normal dungeon group size
|
||||
time_t m_LowPopulationOutsideSince; ///< Time the last player left the dungeon map, 0 if inside
|
||||
// Vote Kick
|
||||
uint8 m_KicksLeft; ///< Number of kicks left
|
||||
bool m_VoteKickActive;
|
||||
|
||||
@@ -300,6 +300,55 @@ void LFGMgr::Update(uint32 diff)
|
||||
|
||||
time_t currTime = GameTime::GetGameTime();
|
||||
|
||||
// LOWPOP_GROUP_LIFECYCLE
|
||||
// A solo low-population LFG group may remain alive outside the dungeon for a
|
||||
// configurable grace period. A timeout of 0 disables automatic cleanup.
|
||||
int32 const lowPopulationOutsideTimeout =
|
||||
sWorld->getIntConfig(CONFIG_DUNGEON_FINDER_LOW_POPULATION_SOLO_GROUP_OUTSIDE_TIMEOUT);
|
||||
|
||||
if (lowPopulationOutsideTimeout > 0)
|
||||
{
|
||||
GuidList expiredLowPopulationGroups;
|
||||
|
||||
for (LfgGroupDataContainer::const_iterator it = GroupsStore.begin(); it != GroupsStore.end(); ++it)
|
||||
{
|
||||
LfgGroupData const& groupData = it->second;
|
||||
time_t const outsideSince = groupData.GetLowPopulationOutsideSince();
|
||||
|
||||
if (!groupData.IsLowPopulation() || groupData.GetPlayerCount() != 1 || !outsideSince)
|
||||
continue;
|
||||
|
||||
if (currTime >= outsideSince + lowPopulationOutsideTimeout)
|
||||
expiredLowPopulationGroups.push_back(it->first);
|
||||
}
|
||||
|
||||
// Disband only after iterating GroupsStore because OnDisband removes
|
||||
// the group's LFG data from this same container.
|
||||
for (GuidList::const_iterator it = expiredLowPopulationGroups.begin(); it != expiredLowPopulationGroups.end(); ++it)
|
||||
{
|
||||
ObjectGuid gguid = *it;
|
||||
Group* group = sGroupMgr->GetGroupByGUID(gguid.GetCounter());
|
||||
|
||||
if (!group)
|
||||
{
|
||||
RemoveGroupData(gguid);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (group->GetMembersCount() != 1)
|
||||
{
|
||||
ClearLowPopulationOutsideTimer(gguid);
|
||||
continue;
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("lfg", "Low-population solo LFG group %s expired after %u seconds outside the dungeon.",
|
||||
gguid.ToString().c_str(), uint32(lowPopulationOutsideTimeout));
|
||||
|
||||
LeaveLfg(gguid);
|
||||
group->Disband();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove obsolete role checks
|
||||
for (LfgRoleCheckContainer::iterator it = RoleChecksStore.begin(); it != RoleChecksStore.end();)
|
||||
{
|
||||
@@ -1013,6 +1062,10 @@ void LFGMgr::MakeNewGroup(LfgProposal const& proposal)
|
||||
ASSERT(dungeon);
|
||||
|
||||
Group* grp = proposal.group ? sGroupMgr->GetGroupByGUID(proposal.group.GetCounter()) : nullptr;
|
||||
bool const lowPopulation = proposal.players.size() < dungeon->GetMaxGroupSize();
|
||||
if (grp)
|
||||
SetLowPopulationGroup(proposal.group, lowPopulation);
|
||||
|
||||
for (GuidList::const_iterator it = players.begin(); it != players.end(); ++it)
|
||||
{
|
||||
ObjectGuid pguid = (*it);
|
||||
@@ -1035,6 +1088,7 @@ void LFGMgr::MakeNewGroup(LfgProposal const& proposal)
|
||||
ObjectGuid gguid = grp->GetGUID();
|
||||
SetState(gguid, LFG_STATE_PROPOSAL);
|
||||
sGroupMgr->AddGroup(grp);
|
||||
SetLowPopulationGroup(gguid, lowPopulation);
|
||||
}
|
||||
else if (group != grp)
|
||||
grp->AddMember(player);
|
||||
@@ -1053,7 +1107,10 @@ void LFGMgr::MakeNewGroup(LfgProposal const& proposal)
|
||||
{
|
||||
uint32 rDungeonId = (*dungeons.begin());
|
||||
LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(rDungeonId);
|
||||
if (dungeon && dungeon->TypeID == LFG_TYPE_RANDOM)
|
||||
// LOWPOP_CLIENT_STATUS
|
||||
// Low-population fallback groups deliberately skip the normal
|
||||
// random-dungeon requeue cooldown.
|
||||
if (dungeon && dungeon->TypeID == LFG_TYPE_RANDOM && !lowPopulation)
|
||||
player->CastSpell(player, LFG_SPELL_DUNGEON_COOLDOWN, false);
|
||||
}
|
||||
}
|
||||
@@ -1941,6 +1998,12 @@ void LFGMgr::SetTicket(ObjectGuid guid, WorldPackets::LFG::RideTicket const& tic
|
||||
PlayersStore[guid].SetTicket(ticket);
|
||||
}
|
||||
|
||||
// LOWPOP_LEAVE_CLEANUP
|
||||
void LFGMgr::ClearTicket(ObjectGuid guid)
|
||||
{
|
||||
PlayersStore[guid].SetTicket(WorldPackets::LFG::RideTicket());
|
||||
}
|
||||
|
||||
void LFGMgr::RemovePlayerData(ObjectGuid guid)
|
||||
{
|
||||
TC_LOG_TRACE("lfg.data.player.remove", "Player: %s", guid.ToString().c_str());
|
||||
@@ -1949,6 +2012,35 @@ void LFGMgr::RemovePlayerData(ObjectGuid guid)
|
||||
PlayersStore.erase(it);
|
||||
}
|
||||
|
||||
// LOWPOP_GROUP_LIFECYCLE
|
||||
void LFGMgr::SetLowPopulationGroup(ObjectGuid gguid, bool enabled)
|
||||
{
|
||||
GroupsStore[gguid].SetLowPopulation(enabled);
|
||||
}
|
||||
|
||||
bool LFGMgr::IsLowPopulationGroup(ObjectGuid gguid)
|
||||
{
|
||||
LfgGroupDataContainer::const_iterator it = GroupsStore.find(gguid);
|
||||
return it != GroupsStore.end() && it->second.IsLowPopulation();
|
||||
}
|
||||
|
||||
void LFGMgr::StartLowPopulationOutsideTimer(ObjectGuid gguid)
|
||||
{
|
||||
LfgGroupDataContainer::iterator it = GroupsStore.find(gguid);
|
||||
if (it == GroupsStore.end() || !it->second.IsLowPopulation())
|
||||
return;
|
||||
|
||||
if (!it->second.GetLowPopulationOutsideSince())
|
||||
it->second.SetLowPopulationOutsideSince(GameTime::GetGameTime());
|
||||
}
|
||||
|
||||
void LFGMgr::ClearLowPopulationOutsideTimer(ObjectGuid gguid)
|
||||
{
|
||||
LfgGroupDataContainer::iterator it = GroupsStore.find(gguid);
|
||||
if (it != GroupsStore.end())
|
||||
it->second.ClearLowPopulationOutsideSince();
|
||||
}
|
||||
|
||||
void LFGMgr::RemoveGroupData(ObjectGuid guid)
|
||||
{
|
||||
TC_LOG_TRACE("lfg.data.group.remove", "Group: %s", guid.ToString().c_str());
|
||||
|
||||
@@ -395,6 +395,14 @@ class TC_GAME_API LFGMgr
|
||||
uint8 RemovePlayerFromGroup(ObjectGuid gguid, ObjectGuid guid);
|
||||
/// Adds player to group
|
||||
void AddPlayerToGroup(ObjectGuid gguid, ObjectGuid guid);
|
||||
/// Marks or clears a group as a low-population dungeon group
|
||||
void SetLowPopulationGroup(ObjectGuid gguid, bool enabled);
|
||||
/// Returns true if the group was started through the low-population fallback
|
||||
bool IsLowPopulationGroup(ObjectGuid gguid);
|
||||
/// Starts the outside-dungeon cleanup timer for a solo low-population group
|
||||
void StartLowPopulationOutsideTimer(ObjectGuid gguid);
|
||||
/// Clears the outside-dungeon cleanup timer
|
||||
void ClearLowPopulationOutsideTimer(ObjectGuid gguid);
|
||||
|
||||
// LFGHandler
|
||||
/// Get locked dungeons
|
||||
@@ -427,6 +435,8 @@ class TC_GAME_API LFGMgr
|
||||
void LeaveLfg(ObjectGuid guid, bool disconnected = false);
|
||||
/// Gets unique join queue data
|
||||
WorldPackets::LFG::RideTicket const* GetTicket(ObjectGuid guid) const;
|
||||
/// Clears the player's LFG ride ticket
|
||||
void ClearTicket(ObjectGuid guid);
|
||||
|
||||
// LfgQueue
|
||||
/// Get last lfg state (NONE, DUNGEON or FINISHED_DUNGEON)
|
||||
|
||||
@@ -92,6 +92,9 @@ void LFGPlayerScript::OnMapChanged(Player* player)
|
||||
return;
|
||||
}
|
||||
|
||||
if (sLFGMgr->IsLowPopulationGroup(group->GetGUID()))
|
||||
sLFGMgr->ClearLowPopulationOutsideTimer(group->GetGUID());
|
||||
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
if (Player* member = itr->GetSource())
|
||||
player->GetSession()->SendNameQueryOpcode(member->GetGUID());
|
||||
@@ -104,10 +107,19 @@ void LFGPlayerScript::OnMapChanged(Player* player)
|
||||
Group* group = player->GetGroup();
|
||||
if (group && group->GetMembersCount() == 1)
|
||||
{
|
||||
sLFGMgr->LeaveLfg(group->GetGUID());
|
||||
group->Disband();
|
||||
TC_LOG_DEBUG("lfg", "LFGPlayerScript::OnMapChanged, Player %s(%s) is last in the lfggroup so we disband the group.",
|
||||
player->GetName().c_str(), player->GetGUID().ToString().c_str());
|
||||
if (sLFGMgr->IsLowPopulationGroup(group->GetGUID()))
|
||||
{
|
||||
sLFGMgr->StartLowPopulationOutsideTimer(group->GetGUID());
|
||||
TC_LOG_DEBUG("lfg", "LFGPlayerScript::OnMapChanged, Player %s(%s) left the dungeon as the last member of a low-population LFG group. Starting outside timer.",
|
||||
player->GetName().c_str(), player->GetGUID().ToString().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
sLFGMgr->LeaveLfg(group->GetGUID());
|
||||
group->Disband();
|
||||
TC_LOG_DEBUG("lfg", "LFGPlayerScript::OnMapChanged, Player %s(%s) is last in the lfggroup so we disband the group.",
|
||||
player->GetName().c_str(), player->GetGUID().ToString().c_str());
|
||||
}
|
||||
}
|
||||
player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW);
|
||||
}
|
||||
@@ -155,6 +167,7 @@ void LFGGroupScript::OnRemoveMember(Group* group, ObjectGuid guid, RemoveMethod
|
||||
gguid.ToString().c_str(), guid.ToString().c_str(), method, kicker.ToString().c_str(), (reason ? reason : ""));
|
||||
|
||||
bool isLFG = group->isLFGGroup();
|
||||
bool lowPopulation = isLFG && sLFGMgr->IsLowPopulationGroup(gguid);
|
||||
|
||||
if (isLFG && method == GROUP_REMOVEMETHOD_KICK) // Player have been kicked
|
||||
{
|
||||
@@ -183,6 +196,16 @@ void LFGGroupScript::OnRemoveMember(Group* group, ObjectGuid guid, RemoveMethod
|
||||
|
||||
if (Player* player = ObjectAccessor::FindPlayer(guid))
|
||||
{
|
||||
// LOWPOP_LEAVE_CLEANUP
|
||||
// Every voluntary leaver from a low-population LFG group gets a fully
|
||||
// cleared personal LFG ticket/status. Remaining group members stay.
|
||||
if (lowPopulation && method == GROUP_REMOVEMETHOD_LEAVE)
|
||||
{
|
||||
sLFGMgr->ClearTicket(guid);
|
||||
player->GetSession()->SendLfgUpdateStatus(LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE), true);
|
||||
player->GetSession()->SendLfgUpdateStatus(LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE), false);
|
||||
}
|
||||
|
||||
if (method == GROUP_REMOVEMETHOD_LEAVE && state == LFG_STATE_DUNGEON &&
|
||||
players >= LFG_GROUP_KICK_VOTES_NEEDED)
|
||||
player->CastSpell(player, LFG_SPELL_DUNGEON_DESERTER, true);
|
||||
|
||||
@@ -671,7 +671,7 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R
|
||||
|
||||
SendRaidMarkerUpdateToPlayer(guid, true);
|
||||
|
||||
if (isLFGGroup() && GetMembersCount() == 1)
|
||||
if (isLFGGroup() && GetMembersCount() == 1 && !sLFGMgr->IsLowPopulationGroup(GetGUID()))
|
||||
{
|
||||
Player* leader = ObjectAccessor::FindConnectedPlayer(GetLeaderGUID());
|
||||
uint32 mapId = sLFGMgr->GetDungeonMapId(GetGUID());
|
||||
|
||||
@@ -354,10 +354,23 @@ void WorldSession::SendLfgUpdateStatus(lfg::LfgUpdateData const& updateData, boo
|
||||
join = true;
|
||||
break;
|
||||
case lfg::LFG_UPDATETYPE_UPDATE_STATUS:
|
||||
{
|
||||
// LOWPOP_CLIENT_STATUS
|
||||
// A low-population LFG group can legitimately remain active with
|
||||
// one player outside the dungeon. Keep it client-side joined so
|
||||
// the normal LFG dungeon controls remain available.
|
||||
bool lowPopulationDungeon = false;
|
||||
if (Group* group = GetPlayer()->GetGroup())
|
||||
lowPopulationDungeon = group->isLFGGroup() && sLFGMgr->IsLowPopulationGroup(group->GetGUID());
|
||||
|
||||
join = updateData.state != lfg::LFG_STATE_ROLECHECK && updateData.state != lfg::LFG_STATE_NONE &&
|
||||
updateData.state != lfg::LFG_STATE_DUNGEON && updateData.state != lfg::LFG_STATE_FINISHED_DUNGEON;
|
||||
(lowPopulationDungeon ||
|
||||
(updateData.state != lfg::LFG_STATE_DUNGEON &&
|
||||
updateData.state != lfg::LFG_STATE_FINISHED_DUNGEON));
|
||||
|
||||
queued = updateData.state == lfg::LFG_STATE_QUEUED || updateData.state == lfg::LFG_STATE_RAIDBROWSER;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1527,6 +1527,8 @@ void World::LoadConfigSettings(bool reload)
|
||||
sConfigMgr->GetIntDefault("DungeonFinder.LowPopulation.FallbackDelay", 60);
|
||||
m_int_configs[CONFIG_DUNGEON_FINDER_LOW_POPULATION_MIN_PLAYERS] =
|
||||
sConfigMgr->GetIntDefault("DungeonFinder.LowPopulation.MinPlayers", 1);
|
||||
m_int_configs[CONFIG_DUNGEON_FINDER_LOW_POPULATION_SOLO_GROUP_OUTSIDE_TIMEOUT] =
|
||||
sConfigMgr->GetIntDefault("DungeonFinder.LowPopulation.SoloGroupOutsideTimeout", 300);
|
||||
|
||||
if (m_int_configs[CONFIG_DUNGEON_FINDER_LOW_POPULATION_MIN_PLAYERS] < 1)
|
||||
{
|
||||
|
||||
@@ -367,6 +367,7 @@ enum WorldIntConfigs : uint8
|
||||
CONFIG_LFG_OPTIONSMASK,
|
||||
CONFIG_DUNGEON_FINDER_LOW_POPULATION_FALLBACK_DELAY,
|
||||
CONFIG_DUNGEON_FINDER_LOW_POPULATION_MIN_PLAYERS,
|
||||
CONFIG_DUNGEON_FINDER_LOW_POPULATION_SOLO_GROUP_OUTSIDE_TIMEOUT,
|
||||
CONFIG_MAX_INSTANCES_PER_HOUR,
|
||||
CONFIG_WARDEN_CLIENT_RESPONSE_DELAY,
|
||||
CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF,
|
||||
|
||||
Reference in new issue
Block a user