Core/Packets: updated more lfg packets to new packet class handling

This commit is contained in:
Ovahlord
2019-05-31 17:35:51 +02:00
parent 9788cc54a1
commit 4b5ad5168d
11 changed files with 428 additions and 331 deletions

View File

@@ -60,7 +60,7 @@ enum LfgUpdateType
LFG_UPDATETYPE_JOIN_LFG_OBJECT_FAILED = 45,
};
enum LfgState
enum LfgState : uint8
{
LFG_STATE_NONE, // Not using LFG / LFR
LFG_STATE_ROLECHECK, // Rolecheck active

View File

@@ -549,6 +549,11 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
SetComment(guid, comment);
WorldPackets::LFG::RideTicket ticket;
ticket.RequesterGuid = guid;
ticket.Id = GetQueueId(gguid);
ticket.Type = WorldPackets::LFG::RideType::Lfg;
ticket.Time = int32(time(nullptr));
std::string debugNames = "";
if (grp) // Begin rolecheck
{
@@ -576,6 +581,7 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
ObjectGuid pguid = plrg->GetGUID();
plrg->GetSession()->SendLfgUpdateStatus(updateData, true);
SetState(pguid, LFG_STATE_ROLECHECK);
SetTicket(pguid, ticket);
if (!isContinue)
SetSelectedDungeons(pguid, dungeons);
roleCheck.roles[pguid] = 0;
@@ -608,18 +614,12 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
SetCallToArmsRewardEnligible(player->GetGUID(), true);
// Send update to player
player->GetSession()->SendLfgJoinResult(joinData);
if (!isRaid)
{
player->GetSession()->SendLfgUpdateStatus(LfgUpdateData(LFG_UPDATETYPE_JOIN_QUEUE, dungeons, comment), false);
SetState(gguid, LFG_STATE_QUEUED);
}
else
{
player->GetSession()->SendLfgUpdateStatus(LfgUpdateData(LFG_UPDATETYPE_JOIN_RAIDBROWSER, dungeons, comment), false);
SetState(gguid, LFG_STATE_RAIDBROWSER);
}
SetTicket(guid, ticket);
SetRoles(guid, roles);
player->GetSession()->SendLfgUpdateStatus(LfgUpdateData(LFG_UPDATETYPE_JOIN_QUEUE_INITIAL, dungeons, comment), false);
SetState(guid, isRaid ? LFG_STATE_RAIDBROWSER : LFG_STATE_QUEUED);
player->GetSession()->SendLfgUpdateStatus(LfgUpdateData(isRaid ? LFG_UPDATETYPE_JOIN_RAIDBROWSER : LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, comment), false);
player->GetSession()->SendLfgJoinResult(joinData);
debugNames.append(player->GetName());
}
@@ -704,6 +704,15 @@ void LFGMgr::LeaveLfg(ObjectGuid guid, bool disconnected)
}
}
WorldPackets::LFG::RideTicket const* LFGMgr::GetTicket(ObjectGuid guid) const
{
auto itr = PlayersStore.find(guid);
if (itr != PlayersStore.end())
return &itr->second.GetTicket();
return nullptr;
}
/**
Update the Role check info with the player selected role.
@@ -755,11 +764,7 @@ void LFGMgr::UpdateRoleCheck(ObjectGuid gguid, ObjectGuid guid /* = ObjectGuid::
}
}
LfgJoinResult joinResult = LFG_JOIN_FAILED;
if (roleCheck.state == LFG_ROLECHECK_MISSING_ROLE || roleCheck.state == LFG_ROLECHECK_WRONG_ROLES)
joinResult = LFG_JOIN_ROLE_CHECK_FAILED;
LfgJoinResultData joinData = LfgJoinResultData(joinResult, roleCheck.state);
LfgJoinResultData joinData = LfgJoinResultData(LFG_JOIN_ROLE_CHECK_FAILED, roleCheck.state);
for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it)
{
ObjectGuid pguid = it->first;
@@ -1363,7 +1368,7 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
{
TC_LOG_DEBUG("lfg.teleport", "Player %s not in group/lfggroup or dungeon not found!",
player->GetName().c_str());
player->GetSession()->SendLfgTeleportError(uint8(LFG_TELEPORTERROR_INVALID_LOCATION));
player->GetSession()->SendLfgTeleportError(uint8(LFG_TELEPORT_RESULT_NO_RETURN_LOCATION));
return;
}
@@ -1377,20 +1382,20 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
return;
}
LfgTeleportError error = LFG_TELEPORTERROR_OK;
LfgTeleportResult error = LFG_TELEPORT_RESULT_NONE;
if (!player->IsAlive())
error = LFG_TELEPORTERROR_PLAYER_DEAD;
error = LFG_TELEPORT_RESULT_DEAD;
else if (player->IsFalling() || player->HasUnitState(UNIT_STATE_JUMPING))
error = LFG_TELEPORTERROR_FALLING;
error = LFG_TELEPORT_RESULT_FALLING;
else if (player->IsMirrorTimerActive(FATIGUE_TIMER))
error = LFG_TELEPORTERROR_FATIGUE;
error = LFG_TELEPORT_RESULT_EXHAUSTION;
else if (player->GetVehicle())
error = LFG_TELEPORTERROR_IN_VEHICLE;
error = LFG_TELEPORT_RESULT_ON_TRANSPORT;
else if (player->GetCharmGUID())
error = LFG_TELEPORTERROR_CHARMING;
error = LFG_TELEPORT_RESULT_IMMUNE_TO_SUMMONS;
else if (player->HasAura(9454)) // check Freeze debuff
error = LFG_TELEPORTERROR_INVALID_LOCATION;
error = LFG_TELEPORT_RESULT_NO_RETURN_LOCATION;
else if (player->GetMapId() != uint32(dungeon->map)) // Do not teleport players in dungeon to the entrance
{
uint32 mapid = dungeon->map;
@@ -1436,12 +1441,12 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
}
if (!player->TeleportTo(mapid, x, y, z, orientation))
error = LFG_TELEPORTERROR_INVALID_LOCATION;
error = LFG_TELEPORT_RESULT_NO_RETURN_LOCATION;
}
else
{
if (player->IsInCombat())
error = LFG_TELEPORTERROR_IN_COMBAT;
error = LFG_TELEPORT_RESULT_IMMUNE_TO_SUMMONS;
else if (player->GetMapId() == uint32(dungeon->map))
{
player->SetLFGLeavePoint();
@@ -1449,7 +1454,7 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
}
}
if (error != LFG_TELEPORTERROR_OK)
if (error != LFG_TELEPORT_RESULT_NONE)
player->GetSession()->SendLfgTeleportError(uint8(error));
TC_LOG_DEBUG("lfg.teleport", "Player %s is being teleported in to map %u "
@@ -1948,6 +1953,11 @@ void LFGMgr::DecreaseKicksLeft(ObjectGuid guid)
TC_LOG_TRACE("lfg.data.group.kicksleft.decrease", "Group: %s, Kicks: %u", guid.ToString().c_str(), GroupsStore[guid].GetKicksLeft());
}
void LFGMgr::SetTicket(ObjectGuid guid, WorldPackets::LFG::RideTicket const& ticket)
{
PlayersStore[guid].SetTicket(ticket);
}
void LFGMgr::RemovePlayerData(ObjectGuid guid)
{
TC_LOG_TRACE("lfg.data.player.remove", "Player: %s", guid.ToString().c_str());

View File

@@ -33,6 +33,14 @@ class Map;
struct LFGDungeonEntry;
enum Difficulty : uint8;
namespace WorldPackets
{
namespace LFG
{
struct RideTicket;
}
}
namespace lfg
{
@@ -82,17 +90,21 @@ enum LfgProposalState
};
/// Teleport errors
enum LfgTeleportError
enum LfgTeleportResult : uint8
{
// 7 = "You can't do that right now" | 5 = No client reaction
LFG_TELEPORTERROR_OK = 0, // Internal use
LFG_TELEPORTERROR_PLAYER_DEAD = 1,
LFG_TELEPORTERROR_FALLING = 2,
LFG_TELEPORTERROR_IN_VEHICLE = 3,
LFG_TELEPORTERROR_FATIGUE = 4,
LFG_TELEPORTERROR_INVALID_LOCATION = 6,
LFG_TELEPORTERROR_CHARMING = 7,
LFG_TELEPORTERROR_IN_COMBAT = 8
LFG_TELEPORT_RESULT_NONE = 0, // Internal use
LFG_TELEPORT_RESULT_DEAD = 1,
LFG_TELEPORT_RESULT_FALLING = 2,
LFG_TELEPORT_RESULT_ON_TRANSPORT = 3,
LFG_TELEPORT_RESULT_EXHAUSTION = 4,
LFG_TELEPORT_RESULT_NO_RETURN_LOCATION = 6,
LFG_TELEPORT_RESULT_IMMUNE_TO_SUMMONS = 8 // FIXME - It can be 7 or 8 (Need proper data)
// unknown values
//LFG_TELEPORT_RESULT_NOT_IN_DUNGEON,
//LFG_TELEPORT_RESULT_NOT_ALLOWED,
//LFG_TELEPORT_RESULT_ALREADY_IN_DUNGEON
};
/// Queue join results
@@ -187,14 +199,13 @@ struct LfgUpdateData
// Data needed by SMSG_LFG_QUEUE_STATUS
struct LfgQueueStatusData
{
LfgQueueStatusData(uint8 _queueId = 0, uint32 _dungeonId = 0, time_t _joinTime = 0, int32 _waitTime = -1, int32 _waitTimeAvg = -1, int32 _waitTimeTank = -1, int32 _waitTimeHealer = -1,
LfgQueueStatusData(uint8 _queueId = 0, uint32 _dungeonId = 0, int32 _waitTime = -1, int32 _waitTimeAvg = -1, int32 _waitTimeTank = -1, int32 _waitTimeHealer = -1,
int32 _waitTimeDps = -1, uint32 _queuedTime = 0, uint8 _tanks = 0, uint8 _healers = 0, uint8 _dps = 0) :
queueId(_queueId), dungeonId(_dungeonId), joinTime(_joinTime), waitTime(_waitTime), waitTimeAvg(_waitTimeAvg), waitTimeTank(_waitTimeTank),
queueId(_queueId), dungeonId(_dungeonId), waitTime(_waitTime), waitTimeAvg(_waitTimeAvg), waitTimeTank(_waitTimeTank),
waitTimeHealer(_waitTimeHealer), waitTimeDps(_waitTimeDps), queuedTime(_queuedTime), tanks(_tanks), healers(_healers), dps(_dps) { }
uint8 queueId;
uint32 dungeonId;
time_t joinTime;
int32 waitTime;
int32 waitTimeAvg;
int32 waitTimeTank;
@@ -435,6 +446,8 @@ class TC_GAME_API LFGMgr
void JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string const& comment);
/// Leaves lfg
void LeaveLfg(ObjectGuid guid, bool disconnected = false);
/// Gets unique join queue data
WorldPackets::LFG::RideTicket const* GetTicket(ObjectGuid guid) const;
// LfgQueue
/// Get last lfg state (NONE, DUNGEON or FINISHED_DUNGEON)
@@ -467,6 +480,7 @@ class TC_GAME_API LFGMgr
void SetDungeon(ObjectGuid guid, uint32 dungeon);
void SetSelectedDungeons(ObjectGuid guid, LfgDungeonSet const& dungeons);
void DecreaseKicksLeft(ObjectGuid guid);
void SetTicket(ObjectGuid guid, WorldPackets::LFG::RideTicket const& ticket);
void SetState(ObjectGuid guid, LfgState state);
void SetVoteKick(ObjectGuid gguid, bool active);
void RemovePlayerData(ObjectGuid guid);

View File

@@ -26,6 +26,11 @@ LfgPlayerData::LfgPlayerData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NO
LfgPlayerData::~LfgPlayerData() { }
void LfgPlayerData::SetTicket(WorldPackets::LFG::RideTicket const& ticket)
{
m_Ticket = ticket;
}
void LfgPlayerData::SetState(LfgState state)
{
switch (state)
@@ -84,6 +89,11 @@ void LfgPlayerData::SetCallToArmsRewardEnligible(bool apply)
m_CallToArmsRewardEnligible = apply;
}
WorldPackets::LFG::RideTicket const& LfgPlayerData::GetTicket() const
{
return m_Ticket;
}
LfgState LfgPlayerData::GetState() const
{
return m_State;

View File

@@ -19,6 +19,7 @@
#define _LFGPLAYERDATA_H
#include "LFG.h"
#include "LFGPacketsCommon.h"
namespace lfg
{
@@ -33,6 +34,7 @@ class TC_GAME_API LfgPlayerData
~LfgPlayerData();
// General
void SetTicket(WorldPackets::LFG::RideTicket const& ticket);
void SetState(LfgState state);
void RestoreState();
void SetTeam(uint8 team);
@@ -44,6 +46,7 @@ class TC_GAME_API LfgPlayerData
void SetSelectedDungeons(const LfgDungeonSet& dungeons);
// General
WorldPackets::LFG::RideTicket const& GetTicket() const;
LfgState GetState() const;
LfgState GetOldState() const;
uint8 GetTeam() const;
@@ -60,6 +63,7 @@ class TC_GAME_API LfgPlayerData
private:
// General
WorldPackets::LFG::RideTicket m_Ticket; ///< Join ticket
LfgState m_State; ///< State if group in LFG
LfgState m_OldState; ///< Old State - Used to restore state after failed Rolecheck/Proposal
// Player

View File

@@ -657,7 +657,7 @@ void LFGQueue::UpdateQueueTimers(uint8 queueId, time_t currTime, uint32 &tankCou
if (queueinfo.bestCompatible.empty())
FindBestCompatibleInQueue(itQueue);
LfgQueueStatusData queueData(queueId, dungeonId, queueinfo.joinTime, waitTime, wtAvg, wtTank, wtHealer, wtDps, queuedTime, queueinfo.tanks, queueinfo.healers, queueinfo.dps);
LfgQueueStatusData queueData(queueId, dungeonId, waitTime, wtAvg, wtTank, wtHealer, wtDps, queuedTime, queueinfo.tanks, queueinfo.healers, queueinfo.dps);
for (LfgRolesMap::const_iterator itPlayer = queueinfo.roles.begin(); itPlayer != queueinfo.roles.end(); ++itPlayer)
{
ObjectGuid pguid = itPlayer->first;

View File

@@ -42,10 +42,7 @@ void LFGPlayerScript::OnLogout(Player* player)
return;
if (!player->GetGroup())
{
player->GetSession()->SendLfgLfrList(false);
sLFGMgr->LeaveLfg(player->GetGUID());
}
else if (player->GetSession()->PlayerDisconnected())
sLFGMgr->LeaveLfg(player->GetGUID(), true);
}

View File

@@ -27,116 +27,6 @@
#include "WorldPacket.h"
#include "WorldSession.h"
void BuildPlayerLockDungeonBlock(WorldPacket& data, lfg::LfgLockMap const& lock)
{
data << uint32(lock.size()); // Size of lock dungeons
for (lfg::LfgLockMap::const_iterator it = lock.begin(); it != lock.end(); ++it)
{
TC_LOG_TRACE("lfg", "BuildPlayerLockDungeonBlock:: DungeonID: %u Lock status: %u Required itemLevel: %u Current itemLevel: %f",
(it->first & 0x00FFFFFF), it->second.lockStatus, it->second.requiredItemLevel, it->second.currentItemLevel);
data << uint32(it->first); // Dungeon entry (id + type)
data << uint32(it->second.lockStatus); // Lock status
data << uint32(it->second.requiredItemLevel); // Required itemLevel
data << uint32(it->second.currentItemLevel); // Current itemLevel
}
}
void BuildPartyLockDungeonBlock(WorldPacket& data, lfg::LfgLockPartyMap const& lockMap)
{
data << uint8(lockMap.size());
for (lfg::LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it)
{
data << uint64(it->first); // Player guid
BuildPlayerLockDungeonBlock(data, it->second);
}
}
void BuildQuestReward(WorldPacket& data, Quest const* quest, Quest const* bonusQuest, Player* player)
{
uint8 rewCount = quest->GetRewItemsCount() + quest->GetRewCurrencyCount();
uint32 rewMoney = player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) ? quest->GetRewOrReqMoney() : quest->GetRewMoneyMaxLevel();
uint32 rewXP = player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) ? quest->XPValue(player) : 0;
if (bonusQuest)
{
rewCount += bonusQuest->GetRewItemsCount() + bonusQuest->GetRewCurrencyCount();
rewMoney += player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) ? bonusQuest->GetRewOrReqMoney() : bonusQuest->GetRewMoneyMaxLevel();
rewXP += player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) ? bonusQuest->XPValue(player) : 0;
}
data << uint32(rewMoney);
data << uint32(rewXP);
data << uint8(rewCount);
if (rewCount)
{
for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
{
if (uint32 currencyId = quest->RewardCurrencyId[i])
{
uint32 rewardCurrencyCount = quest->RewardCurrencyCount[i];
CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(currencyId);
if (currency->Flags & CURRENCY_FLAG_HIGH_PRECISION)
rewardCurrencyCount = rewardCurrencyCount * CURRENCY_PRECISION;
data << uint32(currencyId);
data << uint32(0);
data << uint32(rewardCurrencyCount);
data << uint8(1); // Is currency
}
}
if (bonusQuest)
{
for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
{
if (uint32 currencyId = bonusQuest->RewardCurrencyId[i])
{
uint32 rewardCurrencyCount = bonusQuest->RewardCurrencyCount[i];
CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(currencyId);
if (currency->Flags & CURRENCY_FLAG_HIGH_PRECISION)
rewardCurrencyCount = rewardCurrencyCount * CURRENCY_PRECISION;
data << uint32(currencyId);
data << uint32(0);
data << uint32(rewardCurrencyCount);
data << uint8(1); // Is currency
}
}
}
for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
{
if (uint32 itemId = quest->RewardItemId[i])
{
ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId);
data << uint32(itemId);
data << uint32(item ? item->DisplayInfoID : 0);
data << uint32(quest->RewardItemIdCount[i]);
data << uint8(0); // Is currency
}
}
if (bonusQuest)
{
for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
{
if (uint32 itemId = bonusQuest->RewardItemId[i])
{
ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId);
data << uint32(itemId);
data << uint32(item ? item->DisplayInfoID : 0);
data << uint32(bonusQuest->RewardItemIdCount[i]);
data << uint8(0); // Is currency
}
}
}
}
}
void WorldSession::HandleLfgJoinOpcode(WorldPackets::LFG::LFGJoin& lfgJoin)
{
if (!sLFGMgr->isOptionEnabled(lfg::LFG_OPTION_ENABLE_DUNGEON_FINDER | lfg::LFG_OPTION_ENABLE_RAID_BROWSER) ||
@@ -236,159 +126,96 @@ void WorldSession::HandleLfgGetLockInfoOpcode(WorldPackets::LFG::LFGGetSystemInf
void WorldSession::SendLfgPlayerLockInfo()
{
Player* player = GetPlayer();
ObjectGuid guid = player->GetGUID();
TC_LOG_DEBUG("lfg", "SMSG_LFG_PLAYER_INFO %s", GetPlayerInfo().c_str());
// Get Random dungeons that can be done at a certain level and expansion
uint8 level = player->getLevel();
lfg::LfgDungeonSet const& randomDungeons = sLFGMgr->GetRandomAndSeasonalDungeons(level, player->GetSession()->Expansion());
uint8 level = _player->getLevel();
lfg::LfgDungeonSet const& randomDungeons = sLFGMgr->GetRandomAndSeasonalDungeons(level, _player->GetSession()->Expansion());
WorldPackets::LFG::LFGPlayerInfo lfgPlayerInfo;
// Get player locked Dungeons
lfg::LfgLockMap const& lock = sLFGMgr->GetLockedDungeons(guid);
uint32 rsize = uint32(randomDungeons.size());
uint32 lsize = uint32(lock.size());
for (auto const& lock : sLFGMgr->GetLockedDungeons(_player->GetGUID()))
lfgPlayerInfo.BlackList.Slot.emplace_back(lock.first, lock.second.lockStatus, lock.second.requiredItemLevel, lock.second.currentItemLevel);
TC_LOG_DEBUG("lfg", "SMSG_LFG_PLAYER_INFO %s", GetPlayerInfo().c_str());
WorldPacket data(SMSG_LFG_PLAYER_INFO, 1 + rsize * (4 + 1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4) + 4 + lsize * (1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4));
data << uint8(randomDungeons.size()); // Random Dungeon count
for (lfg::LfgDungeonSet::const_iterator it = randomDungeons.begin(); it != randomDungeons.end(); ++it)
for (uint32 slot : randomDungeons)
{
uint32 dungeonId = *it;
data << uint32(dungeonId); // Dungeon Entry (id + type)
lfg::LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(dungeonId, level);
bool firstCompletion = false;
Quest const* currentQuest = nullptr;
uint32 rewValorPoints = 0;
lfgPlayerInfo.Dungeon.emplace_back();
WorldPackets::LFG::LfgPlayerDungeonInfo& playerDungeonInfo = lfgPlayerInfo.Dungeon.back();
playerDungeonInfo.Slot = slot;
if (reward)
bool firstReward = false;
Quest const* currentQuest = nullptr;
if (lfg::LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(slot, level))
{
if (Quest const* firstQuest = sObjectMgr->GetQuestTemplate(reward->firstQuest))
{
firstCompletion = player->CanRewardQuest(firstQuest, false);
firstReward = _player->CanRewardQuest(firstQuest, false);
if (reward->completionsPerPeriod)
firstCompletion = player->SatisfyFirstLFGReward(dungeonId & 0x00FFFFFF, reward->completionsPerPeriod);
firstReward = _player->SatisfyFirstLFGReward(slot & 0x00FFFFFF, reward->completionsPerPeriod);
if (firstCompletion)
if (firstReward)
currentQuest = firstQuest;
for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; i++)
if (firstQuest->RewardCurrencyId[i] == CURRENCY_TYPE_VALOR_POINTS)
rewValorPoints += firstQuest->RewardCurrencyCount[i] * CURRENCY_PRECISION;
}
if (Quest const* otherQuest = sObjectMgr->GetQuestTemplate(reward->otherQuest))
{
if (!firstCompletion)
if (!firstReward)
currentQuest = otherQuest;
for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; i++)
if (otherQuest->RewardCurrencyId[i] == CURRENCY_TYPE_VALOR_POINTS)
rewValorPoints += otherQuest->RewardCurrencyCount[i] * CURRENCY_PRECISION;
}
}
data << uint8(firstCompletion);
CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(CURRENCY_TYPE_VALOR_POINTS);
if (currency && rewValorPoints && !reward->completionsPerPeriod)
{
uint32 weekCap = player->GetCurrencyWeekCap(currency);
data << uint32(rewValorPoints); // currencyQuantity (valor points from selected dungeon)
data << uint32(weekCap); // some sort of overall cap/weekly cap
data << uint32(CURRENCY_TYPE_VALOR_POINTS); // currencyID (displays name above the cap bar)
data << uint32(0); // tier1Quantity (current valor points from lfr)
data << uint32(weekCap); // tier1Limit (total valor points from lfr)
data << uint32(0); // overallQuantity (current valor points from lfg - always 0)
data << uint32(weekCap); // overallLimit (total valor points from lfg)
data << uint32(player->GetCurrencyOnWeek(CURRENCY_TYPE_VALOR_POINTS, false)); // periodPurseQuantity (valor points this week)
data << uint32(weekCap); // periodPurseLimit (weekly cap)
data << uint32(player->GetCurrency(CURRENCY_TYPE_VALOR_POINTS, false)); // purseQuantity (overall valor points)
data << uint32(0); // purseLimit
data << uint32(rewValorPoints); // some sort of reward for completion
}
else if (firstCompletion && reward && reward->completionsPerPeriod && !reward->dailyReset)
{
data << uint32(1); // currencyQuantity
data << uint32(reward->completionsPerPeriod); // some sort of overall cap/weekly cap
data << uint32(0); // currencyID
data << uint32(0); // tier1Quantity
data << uint32(reward->completionsPerPeriod); // tier1Limit
data << uint32(player->GetFirstRewardCountForDungeonId(dungeonId & 0x00FFFFFF)); // overallQuantity
data << uint32(reward->completionsPerPeriod); // overallLimit
data << uint32(0); // periodPurseQuantity
data << uint32(0); // periodPurseLimit
data << uint32(0); // purseQuantity
data << uint32(0); // purseLimit
data << uint32(1); // some sort of reward for completion
}
else
{
data << uint32(0); // currencyQuantity
data << uint32(0); // some sort of overall cap/weekly cap
data << uint32(0); // currencyID
data << uint32(0); // tier1Quantity
data << uint32(0); // tier1Limit
data << uint32(0); // overallQuantity
data << uint32(0); // overallLimit
data << uint32(0); // periodPurseQuantity
data << uint32(0); // periodPurseLimit
data << uint32(0); // purseQuantity
data << uint32(0); // purseLimit
data << uint32(0); // some sort of reward for completion
}
data << uint32(0); // completedEncounters
bool isCallToArmsEligible = sLFGMgr->IsCallToArmsEnabled() && sLFGMgr->IsCallToArmsEnligible(player, dungeonId & 0x00FFFFFF);
uint8 roleMask = sLFGMgr->GetCallToArmsEnligibleRoles();
data << uint8(isCallToArmsEligible && roleMask); // Call to Arms eligible
Quest const* ctaQuest = sObjectMgr->GetQuestTemplate(lfg::LFG_CALL_TO_ARMS_QUEST);
if (isCallToArmsEligible && roleMask && ctaQuest)
{
if (sLFGMgr->IsCallToArmsRewardEnligible(guid))
roleMask |= sLFGMgr->GetRoles(guid);
bool rewardSent = false;
for (uint8 i = 0; i < 3; i++)
if (firstReward && reward->completionsPerPeriod)
{
data << uint32(roleMask);
if (!rewardSent)
{
rewardSent = true;
BuildQuestReward(data, ctaQuest, nullptr, player);
}
else
{
data << uint32(0);
data << uint32(0);
data << uint8(0);
}
playerDungeonInfo.CompletionQuantity = 1;
playerDungeonInfo.CompletionLimit = reward->completionsPerPeriod;
playerDungeonInfo.SpecificLimit = reward->completionsPerPeriod;
playerDungeonInfo.OverallQuantity = _player->GetFirstRewardCountForDungeonId(slot & 0x00FFFFFF);
playerDungeonInfo.OverallLimit = reward->completionsPerPeriod;
playerDungeonInfo.Quantity = 1;
}
}
else
{
for (uint32 i = 0; i < 3; ++i)
data << uint32(0);
}
if (currentQuest)
BuildQuestReward(data, currentQuest, nullptr, player);
else
{
data << uint32(0); // Money
data << uint32(0); // XP
data << uint8(0); // Reward count
playerDungeonInfo.Rewards.RewardMoney = _player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) ? currentQuest->GetRewOrReqMoney() : currentQuest->GetRewMoneyMaxLevel();
playerDungeonInfo.Rewards.RewardXP = _player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) ? currentQuest->XPValue(_player) : 0;
for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
if (uint32 itemId = currentQuest->RewardItemId[i])
playerDungeonInfo.Rewards.Item.emplace_back(itemId, currentQuest->RewardItemIdCount[i]);
for (uint32 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
if (uint32 currencyId = currentQuest->RewardCurrencyId[i])
if (CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(currencyId))
{
if (currency->Flags & CURRENCY_FLAG_HIGH_PRECISION)
playerDungeonInfo.Rewards.Currency.emplace_back(currencyId, currentQuest->RewardCurrencyCount[i] * CURRENCY_PRECISION);
else
playerDungeonInfo.Rewards.Currency.emplace_back(currencyId, currentQuest->RewardCurrencyCount[i]);
}
}
for (auto itr : playerDungeonInfo.Rewards.Currency)
{
if (itr.CurrencyID == CURRENCY_TYPE_VALOR_POINTS)
{
CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(CURRENCY_TYPE_VALOR_POINTS);
if (!currency)
continue;
uint32 weeklyCap = _player->GetCurrencyWeekCap(currency);
playerDungeonInfo.CompletionQuantity += itr.Quantity;
playerDungeonInfo.CompletionLimit = weeklyCap;
playerDungeonInfo.CompletionCurrencyID = itr.CurrencyID;
playerDungeonInfo.SpecificLimit = weeklyCap;
playerDungeonInfo.OverallLimit = weeklyCap;
playerDungeonInfo.PurseWeeklyQuantity = _player->GetCurrencyOnWeek(CURRENCY_TYPE_VALOR_POINTS, false);
playerDungeonInfo.PurseWeeklyLimit = weeklyCap;
playerDungeonInfo.PurseQuantity = _player->GetCurrency(CURRENCY_TYPE_VALOR_POINTS, false);
playerDungeonInfo.Quantity += itr.Quantity;
}
}
}
BuildPlayerLockDungeonBlock(data, lock);
SendPacket(&data);
SendPacket(lfgPlayerInfo.Write());
}
void WorldSession::SendLfgPartyLockInfo()
@@ -398,8 +225,9 @@ void WorldSession::SendLfgPartyLockInfo()
if (!group)
return;
WorldPackets::LFG::LFGPartyInfo lfgPartyInfo;
// Get the locked dungeons of the other party members
lfg::LfgLockPartyMap lockMap;
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{
Player* plrg = itr->GetSource();
@@ -410,17 +238,15 @@ void WorldSession::SendLfgPartyLockInfo()
if (pguid == guid)
continue;
lockMap[pguid] = sLFGMgr->GetLockedDungeons(pguid);
lfgPartyInfo.Player.emplace_back();
WorldPackets::LFG::LFGBlackList& lfgBlackList = lfgPartyInfo.Player.back();
lfgBlackList.PlayerGuid = pguid;
for (auto const& lock : sLFGMgr->GetLockedDungeons(pguid))
lfgBlackList.Slot.emplace_back(lock.first, lock.second.lockStatus, lock.second.requiredItemLevel, lock.second.currentItemLevel);
}
uint32 size = 0;
for (lfg::LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it)
size += 8 + 4 + uint32(it->second.size()) * (4 + 4 + 4 + 4);
TC_LOG_DEBUG("lfg", "SMSG_LFG_PARTY_INFO %s", GetPlayerInfo().c_str());
WorldPacket data(SMSG_LFG_PARTY_INFO, 1 + size);
BuildPartyLockDungeonBlock(data, lockMap);
SendPacket(&data);
SendPacket(lfgPartyInfo.Write());
}
void WorldSession::HandleLfrJoinOpcode(WorldPacket& recvData)
@@ -468,12 +294,8 @@ void WorldSession::HandleLfgGetStatus(WorldPacket& /*recvData*/)
void WorldSession::SendLfgUpdateStatus(lfg::LfgUpdateData const& updateData, bool party)
{
bool join = false;
bool extraData = false;
bool queued = false;
uint8 size = uint8(updateData.dungeons.size());
ObjectGuid guid = _player->GetGUID();
time_t joinTime = sLFGMgr->GetQueueJoinTime(_player->GetGUID());
uint32 queueId = sLFGMgr->GetQueueId(_player->GetGUID());
switch (updateData.updateType)
{
@@ -483,12 +305,10 @@ void WorldSession::SendLfgUpdateStatus(lfg::LfgUpdateData const& updateData, boo
case lfg::LFG_UPDATETYPE_JOIN_QUEUE:
case lfg::LFG_UPDATETYPE_ADDED_TO_QUEUE: // Rolecheck Success
join = true;
extraData = true;
queued = true;
break;
case lfg::LFG_UPDATETYPE_JOIN_RAIDBROWSER:
join = true;
extraData = true;
break;
case lfg::LFG_UPDATETYPE_PROPOSAL_BEGIN:
join = true;
@@ -504,42 +324,24 @@ void WorldSession::SendLfgUpdateStatus(lfg::LfgUpdateData const& updateData, boo
TC_LOG_DEBUG("lfg", "SMSG_LFG_UPDATE_STATUS %s updatetype: %u, party %s",
GetPlayerInfo().c_str(), updateData.updateType, party ? "true" : "false");
WorldPacket data(SMSG_LFG_UPDATE_STATUS, 1 + 8 + 3 + 2 + 1 + updateData.comment.length() + 4 + 4 + 1 + 1 + 1 + 4 + size);
data.WriteBit(guid[1]);
data.WriteBit(party);
data.WriteBits(size, 24);
data.WriteBit(guid[6]);
data.WriteBit(extraData); // Extra info
data.WriteBits(updateData.comment.length(), 9);
data.WriteBit(guid[4]);
data.WriteBit(guid[7]);
data.WriteBit(guid[2]);
data.WriteBit(join); // LFG Join
data.WriteBit(guid[0]);
data.WriteBit(guid[3]);
data.WriteBit(guid[5]);
data.WriteBit(queued); // Join the queue
WorldPackets::LFG::LFGUpdateStatus lfgUpdateStatus;
if (WorldPackets::LFG::RideTicket const* ticket = sLFGMgr->GetTicket(guid))
lfgUpdateStatus.Ticket = *ticket;
data << uint8(updateData.updateType); // Lfg Update type
data.WriteString(updateData.comment);
data << uint32(queueId); // Queue Id
data << uint32(joinTime); // Join date
data.WriteByteSeq(guid[6]);
for (uint8 i = 0; i < 3; ++i)
data << uint8(0); // unk - Always 0
lfgUpdateStatus.Reason = updateData.updateType;
std::transform(updateData.dungeons.begin(), updateData.dungeons.end(), std::back_inserter(lfgUpdateStatus.Slots), [](uint32 dungeonId)
{
return sLFGMgr->GetLFGDungeonEntry(dungeonId);
});
lfgUpdateStatus.RequestedRoles = sLFGMgr->GetRoles(_player->GetGUID());
//lfgUpdateStatus.SuspendedPlayers;
lfgUpdateStatus.IsParty = party;
lfgUpdateStatus.Joined = join;
lfgUpdateStatus.LfgJoined = updateData.updateType != lfg::LFG_UPDATETYPE_REMOVED_FROM_QUEUE;
lfgUpdateStatus.Queued = queued;
lfgUpdateStatus.Comment = updateData.comment;
data.WriteByteSeq(guid[1]);
data.WriteByteSeq(guid[2]);
data.WriteByteSeq(guid[4]);
data.WriteByteSeq(guid[3]);
data.WriteByteSeq(guid[5]);
data.WriteByteSeq(guid[0]);
data << uint32(3);
data.WriteByteSeq(guid[7]);
for (lfg::LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it)
data << uint32(*it);
SendPacket(&data);
SendPacket(lfgUpdateStatus.Write());
}
void WorldSession::SendLfgRoleChosen(ObjectGuid guid, uint8 roles)
@@ -707,7 +509,7 @@ void WorldSession::SendLfgQueueStatus(lfg::LfgQueueStatusData const& queueData)
data.WriteByteSeq(guid[4]);
data.WriteByteSeq(guid[6]);
data << int32(queueData.waitTime); // Wait Time
data << uint32(queueData.joinTime); // Join time
data << uint32(0); // Join time
data << uint32(queueData.dungeonId); // Dungeon
data << uint32(queueData.queuedTime); // Player wait time in queue
data.WriteByteSeq(guid[5]);
@@ -737,7 +539,7 @@ void WorldSession::SendLfgPlayerReward(lfg::LfgPlayerRewardData const& rewardDat
WorldPacket data(SMSG_LFG_PLAYER_REWARD, 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + itemNum * (4 + 4 + 4));
data << uint32(rewardData.rdungeonEntry); // Random Dungeon Finished
data << uint32(rewardData.sdungeonEntry); // Dungeon Finished
BuildQuestReward(data, rewardData.quest, rewardData.callToArmsQuest,GetPlayer());
//BuildQuestReward(data, rewardData.quest, rewardData.callToArmsQuest,GetPlayer());
SendPacket(&data);
}

View File

@@ -135,3 +135,152 @@ void WorldPackets::LFG::LFGGetSystemInfo::Read()
{
Player = _worldPacket.ReadBit();
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LFGBlackListSlot const& lfgBlackListSlot)
{
data << uint32(lfgBlackListSlot.Slot);
data << uint32(lfgBlackListSlot.Reason);
data << uint32(lfgBlackListSlot.SubReason1);
data << uint32(lfgBlackListSlot.SubReason2);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LFGBlackList const& blackList)
{
if (blackList.PlayerGuid)
data << *blackList.PlayerGuid;
data << uint32(blackList.Slot.size());
for (WorldPackets::LFG::LFGBlackListSlot const& slot : blackList.Slot)
data << slot;
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LfgPlayerQuestRewardItem const& playerQuestRewardItem)
{
ItemTemplate const* item = sObjectMgr->GetItemTemplate(playerQuestRewardItem.ItemID);
data << int32(playerQuestRewardItem.ItemID);
data << int32(item ? item->DisplayInfoID : 0);
data << int32(playerQuestRewardItem.Quantity);
data << uint8(0);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LfgPlayerQuestRewardCurrency const& playerQuestRewardCurrency)
{
data << int32(playerQuestRewardCurrency.CurrencyID);
data << int32(0);
data << int32(playerQuestRewardCurrency.Quantity);
data << uint8(1);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LfgPlayerQuestReward const& playerQuestReward)
{
data << int32(playerQuestReward.RewardMoney);
data << int32(playerQuestReward.RewardXP);
data << uint8(playerQuestReward.Item.size() + playerQuestReward.Currency.size());
for (WorldPackets::LFG::LfgPlayerQuestRewardCurrency const& currency : playerQuestReward.Currency)
data << currency;
for (WorldPackets::LFG::LfgPlayerQuestRewardItem const& item : playerQuestReward.Item)
data << item;
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LfgPlayerDungeonInfo const& playerDungeonInfo)
{
data << uint32(playerDungeonInfo.Slot);
data << uint8(playerDungeonInfo.FirstReward);
data << uint32(playerDungeonInfo.CompletionQuantity);
data << uint32(playerDungeonInfo.CompletionLimit);
data << uint32(playerDungeonInfo.CompletionCurrencyID);
data << uint32(playerDungeonInfo.SpecificQuantity);
data << uint32(playerDungeonInfo.SpecificLimit);
data << uint32(playerDungeonInfo.OverallQuantity);
data << uint32(playerDungeonInfo.OverallLimit);
data << uint32(playerDungeonInfo.PurseWeeklyQuantity);
data << uint32(playerDungeonInfo.PurseWeeklyLimit);
data << uint32(playerDungeonInfo.PurseQuantity);
data << uint32(playerDungeonInfo.PurseLimit);
data << uint32(playerDungeonInfo.Quantity);
data << uint32(playerDungeonInfo.CompletedMask);
data << uint8(playerDungeonInfo.ShortageEligible);
// Todo: Shortage System (Call to Arms)
for (uint8 i = 0; i < 3; i++)
data << uint32(0);
data << playerDungeonInfo.Rewards;
return data;
}
WorldPacket const* WorldPackets::LFG::LFGPlayerInfo::Write()
{
_worldPacket << uint8(Dungeon.size());
for (LfgPlayerDungeonInfo const& playerDungeonInfo : Dungeon)
_worldPacket << playerDungeonInfo;
_worldPacket << uint32(BlackList.Slot.size());
for (WorldPackets::LFG::LFGBlackListSlot const& slot : BlackList.Slot)
_worldPacket << slot;
return &_worldPacket;
}
WorldPacket const* WorldPackets::LFG::LFGPartyInfo::Write()
{
_worldPacket << uint8(Player.size());
for (WorldPackets::LFG::LFGBlackList const& player : Player)
_worldPacket << player;
return &_worldPacket;
}
WorldPacket const* WorldPackets::LFG::LFGUpdateStatus::Write()
{
_worldPacket.WriteBit(Ticket.RequesterGuid[1]);
_worldPacket.WriteBit(IsParty);
_worldPacket.WriteBits(Slots.size(), 24);
_worldPacket.WriteBit(Ticket.RequesterGuid[6]);
_worldPacket.WriteBit(Joined);
_worldPacket.WriteBits(Comment.length(), 9);
_worldPacket.WriteBit(Ticket.RequesterGuid[4]);
_worldPacket.WriteBit(Ticket.RequesterGuid[7]);
_worldPacket.WriteBit(Ticket.RequesterGuid[2]);
_worldPacket.WriteBit(LfgJoined);
_worldPacket.WriteBit(Ticket.RequesterGuid[0]);
_worldPacket.WriteBit(Ticket.RequesterGuid[3]);
_worldPacket.WriteBit(Ticket.RequesterGuid[5]);
_worldPacket.WriteBit(Queued);
_worldPacket << uint8(Reason);
_worldPacket.WriteString(Comment);
_worldPacket << uint32(Ticket.Id);
_worldPacket << uint32(Ticket.Time);
_worldPacket.WriteByteSeq(Ticket.RequesterGuid[6]);
for (uint8 i = 0; i < 3; ++i)
_worldPacket << uint8(0); // unk - Always 0
_worldPacket.WriteByteSeq(Ticket.RequesterGuid[1]);
_worldPacket.WriteByteSeq(Ticket.RequesterGuid[2]);
_worldPacket.WriteByteSeq(Ticket.RequesterGuid[4]);
_worldPacket.WriteByteSeq(Ticket.RequesterGuid[3]);
_worldPacket.WriteByteSeq(Ticket.RequesterGuid[5]);
_worldPacket.WriteByteSeq(Ticket.RequesterGuid[0]);
_worldPacket << uint32(Ticket.Type);
_worldPacket.WriteByteSeq(Ticket.RequesterGuid[7]);
for (uint32 slot : Slots)
_worldPacket << uint32(slot);
return &_worldPacket;
}

View File

@@ -115,6 +115,113 @@ namespace WorldPackets
bool Player = false;
};
struct LFGBlackListSlot
{
LFGBlackListSlot() { }
LFGBlackListSlot(uint32 slot, uint32 reason, int32 subReason1, int32 subReason2)
: Slot(slot), Reason(reason), SubReason1(subReason1), SubReason2(subReason2) { }
uint32 Slot = 0;
uint32 Reason = 0;
int32 SubReason1 = 0;
int32 SubReason2 = 0;
};
struct LFGBlackList
{
Optional<ObjectGuid> PlayerGuid;
std::vector<LFGBlackListSlot> Slot;
};
struct LfgPlayerQuestRewardItem
{
LfgPlayerQuestRewardItem() { }
LfgPlayerQuestRewardItem(int32 itemId, int32 quantity) : ItemID(itemId), Quantity(quantity) { }
int32 ItemID = 0;
int32 Quantity = 0;
};
struct LfgPlayerQuestRewardCurrency
{
LfgPlayerQuestRewardCurrency() { }
LfgPlayerQuestRewardCurrency(int32 currencyID, int32 quantity) : CurrencyID(currencyID), Quantity(quantity) { }
int32 CurrencyID = 0;
int32 Quantity = 0;
};
struct LfgPlayerQuestReward
{
int32 RewardMoney = 0; // Only used by SMSG_LFG_PLAYER_INFO
int32 RewardXP = 0;
std::vector<LfgPlayerQuestRewardItem> Item;
std::vector<LfgPlayerQuestRewardCurrency> Currency; // Only used by SMSG_LFG_PLAYER_INFO
Optional<int32> Honor; // Only used by SMSG_REQUEST_PVP_REWARDS_RESPONSE
};
struct LfgPlayerDungeonInfo
{
uint32 Slot = 0;
uint32 CompletionQuantity = 0;
uint32 CompletionLimit = 0;
uint32 CompletionCurrencyID = 0;
uint32 SpecificQuantity = 0;
uint32 SpecificLimit = 0;
uint32 OverallQuantity = 0;
uint32 OverallLimit = 0;
uint32 PurseWeeklyQuantity = 0;
uint32 PurseWeeklyLimit = 0;
uint32 PurseQuantity = 0;
uint32 PurseLimit = 0;
uint32 Quantity = 0;
uint32 CompletedMask = 0;
uint32 ShortageRoleMask = 0;
bool ShortageEligible = false;
bool FirstReward = false;
LfgPlayerQuestReward Rewards;
LfgPlayerQuestReward ShortageReward;
};
class LFGPlayerInfo final : public ServerPacket
{
public:
LFGPlayerInfo() : ServerPacket(SMSG_LFG_PLAYER_INFO) { }
WorldPacket const* Write() override;
LFGBlackList BlackList;
std::vector<LfgPlayerDungeonInfo> Dungeon;
};
class LFGPartyInfo final : public ServerPacket
{
public:
LFGPartyInfo() : ServerPacket(SMSG_LFG_PARTY_INFO) { }
WorldPacket const* Write() override;
std::vector<LFGBlackList> Player;
};
class LFGUpdateStatus final : public ServerPacket
{
public:
LFGUpdateStatus() : ServerPacket(SMSG_LFG_UPDATE_STATUS) { }
WorldPacket const* Write() override;
RideTicket Ticket;
uint8 Reason = 0;
std::vector<uint32> Slots;
uint32 RequestedRoles = 0;
std::vector<ObjectGuid> SuspendedPlayers;
std::string Comment;
bool IsParty = false;
bool Joined = false;
bool LfgJoined = false;
bool Queued = false;
};
}
}

View File

@@ -67,6 +67,7 @@ struct LfgQueueStatusData;
struct LfgPlayerRewardData;
struct LfgRoleCheck;
struct LfgUpdateData;
enum LfgTeleportResult : uint8;
}
namespace rbac
@@ -86,6 +87,9 @@ namespace WorldPackets
class LFGBootPlayerVote;
class LFGTeleport;
class LFGGetSystemInfo;
class LFGPlayerInfo;
class LFGPartyInfo;
class LFGUpdateStatus;
}
}