diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index bd01ad5850b4c..3f668392fcfa1 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -18,6 +18,7 @@ #include "Battlefield.h" #include "BattlefieldMgr.h" #include "Battleground.h" +#include "BattlegroundPackets.h" #include "CellImpl.h" #include "CreatureTextMgr.h" #include "DBCStores.h" @@ -630,11 +631,10 @@ void Battlefield::RemovePlayerFromResurrectQueue(ObjectGuid playerGuid) void Battlefield::SendAreaSpiritHealerQueryOpcode(Player* player, ObjectGuid guid) { - WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12); - uint32 time = m_LastResurrectTimer; // resurrect every 30 seconds - - data << guid << time; - player->SendDirectMessage(&data); + WorldPackets::Battleground::AreaSpiritHealerTime areaSpiritHealerTime; + areaSpiritHealerTime.HealerGuid = guid; + areaSpiritHealerTime.TimeLeft = m_LastResurrectTimer; + player->SendDirectMessage(areaSpiritHealerTime.Write()); } // ---------------------- diff --git a/src/server/game/Battlegrounds/Arena.cpp b/src/server/game/Battlegrounds/Arena.cpp index 6d5ebc28e4dcb..fb4143bd70b26 100644 --- a/src/server/game/Battlegrounds/Arena.cpp +++ b/src/server/game/Battlegrounds/Arena.cpp @@ -18,6 +18,7 @@ #include "Arena.h" #include "ArenaScore.h" #include "ArenaTeamMgr.h" +#include "BattlegroundPackets.h" #include "Log.h" #include "ObjectAccessor.h" #include "Player.h" @@ -25,37 +26,20 @@ #include "WorldSession.h" #include "WorldStatePackets.h" -void ArenaScore::AppendToPacket(WorldPacket& data) +void ArenaScore::AppendToPacket(WorldPackets::Battleground::PVPLogData_Player& playerData) { - data << uint64(PlayerGuid); + playerData.PlayerGUID = PlayerGuid; - data << uint32(KillingBlows); - data << uint8(TeamId); - data << uint32(DamageDone); - data << uint32(HealingDone); + playerData.Kills = KillingBlows; + playerData.HonorOrFaction = TeamId; + playerData.DamageDone = DamageDone; + playerData.HealingDone = HealingDone; - BuildObjectivesBlock(data); + BuildObjectivesBlock(playerData); } -void ArenaScore::BuildObjectivesBlock(WorldPacket& data) +void ArenaScore::BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& /*playerData*/) { - data << uint32(0); // Objectives Count -} - -void ArenaTeamScore::BuildRatingInfoBlock(WorldPacket& data) -{ - uint32 ratingLost = std::abs(std::min(RatingChange, 0)); - uint32 ratingWon = std::max(RatingChange, 0); - - // should be old rating, new rating, and client will calculate rating change itself - data << uint32(ratingLost); - data << uint32(ratingWon); - data << uint32(MatchmakerRating); -} - -void ArenaTeamScore::BuildTeamInfoBlock(WorldPacket& data) -{ - data << TeamName; } Arena::Arena() diff --git a/src/server/game/Battlegrounds/ArenaScore.h b/src/server/game/Battlegrounds/ArenaScore.h index a8dbcefe127b7..63552a36215df 100644 --- a/src/server/game/Battlegrounds/ArenaScore.h +++ b/src/server/game/Battlegrounds/ArenaScore.h @@ -21,15 +21,15 @@ #include "BattlegroundScore.h" #include -struct TC_GAME_API ArenaScore : public BattlegroundScore +struct TC_GAME_API ArenaScore final : public BattlegroundScore { friend class Arena; protected: ArenaScore(ObjectGuid playerGuid, uint32 team) : BattlegroundScore(playerGuid), TeamId(team == ALLIANCE ? PVP_TEAM_ALLIANCE : PVP_TEAM_HORDE) { } - void AppendToPacket(WorldPacket& data) final override; - void BuildObjectivesBlock(WorldPacket& data) final override; + void AppendToPacket(WorldPackets::Battleground::PVPLogData_Player& playerData) override; + void BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) override; // For Logging purpose std::string ToString() const override @@ -50,8 +50,6 @@ struct TC_GAME_API ArenaTeamScore protected: ArenaTeamScore() : RatingChange(0), MatchmakerRating(0) { } - virtual ~ArenaTeamScore() { } - void Reset() { RatingChange = 0; @@ -66,9 +64,6 @@ struct TC_GAME_API ArenaTeamScore TeamName = teamName; } - void BuildRatingInfoBlock(WorldPacket& data); - void BuildTeamInfoBlock(WorldPacket& data); - int32 RatingChange; uint32 MatchmakerRating; std::string TeamName; diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp index 4883281f00bdc..7bb47cc75e2c0 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.cpp +++ b/src/server/game/Battlegrounds/ArenaTeam.cpp @@ -18,6 +18,7 @@ #include "ArenaTeam.h" #include "ArenaTeamMgr.h" #include "BattlegroundMgr.h" +#include "BattlegroundPackets.h" #include "CalendarPackets.h" #include "CharacterCache.h" #include "DatabaseEnv.h" @@ -337,11 +338,11 @@ void ArenaTeam::DelMember(ObjectGuid guid, bool cleanDb) if (queue.GetPlayerGroupInfoData(playerMember->GetGUID(), &ginfo)) if (!ginfo.IsInvitedToBGInstanceGUID) { - WorldPacket data; playerMember->RemoveBattlegroundQueueId(bgQueue); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, nullptr, i, STATUS_NONE, 0, 0, 0, 0); + WorldPackets::Battleground::BattlefieldStatusNone battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusNone(&battlefieldStatus, i); queue.RemovePlayer(playerMember->GetGUID(), true); - playerMember->GetSession()->SendPacket(&data); + playerMember->SendDirectMessage(battlefieldStatus.Write()); } } } diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 503317d0a5f31..bb08efda2397d 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -18,6 +18,7 @@ #include "Battleground.h" #include "ArenaScore.h" #include "BattlegroundMgr.h" +#include "BattlegroundPackets.h" #include "BattlegroundScore.h" #include "ChatTextBuilder.h" #include "Creature.h" @@ -42,18 +43,21 @@ #include "WorldStatePackets.h" #include -void BattlegroundScore::AppendToPacket(WorldPacket& data) +void BattlegroundScore::AppendToPacket(WorldPackets::Battleground::PVPLogData_Player& playerData) { - data << uint64(PlayerGuid); + playerData.PlayerGUID = PlayerGuid; - data << uint32(KillingBlows); - data << uint32(HonorableKills); - data << uint32(Deaths); - data << uint32(BonusHonor); - data << uint32(DamageDone); - data << uint32(HealingDone); + playerData.Kills = KillingBlows; + playerData.HonorOrFaction = WorldPackets::Battleground::PVPLogData_Honor + { + .HonorKills = HonorableKills, + .Deaths = Deaths, + .ContributionPoints = BonusHonor + }; + playerData.DamageDone = DamageDone; + playerData.HealingDone = HealingDone; - BuildObjectivesBlock(data); + BuildObjectivesBlock(playerData); } template @@ -461,11 +465,10 @@ inline void Battleground::_ProcessJoin(uint32 diff) if (Player* player = ObjectAccessor::FindPlayer(itr->first)) { // BG Status packet - WorldPacket status; BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(m_TypeID, GetBracketId(), GetArenaType()); - uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&status, this, queueSlot, STATUS_IN_PROGRESS, 0, GetStartTime(), GetArenaType(), player->GetBGTeam()); - player->SendDirectMessage(&status); + WorldPackets::Battleground::BattlefieldStatusActive battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusActive(&battlefieldStatus, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), bgQueueTypeId); + player->SendDirectMessage(battlefieldStatus.Write()); player->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); player->ResetAllPowers(); @@ -716,8 +719,9 @@ void Battleground::EndBattleground(uint32 winner) //we must set it this way, because end time is sent in packet! m_EndTime = TIME_TO_AUTOREMOVE; - WorldPacket pvpLogData; - BuildPvPLogDataPacket(pvpLogData); + WorldPackets::Battleground::PVPMatchStatistics pvpMatchStatistics; + BuildPvPLogDataPacket(pvpMatchStatistics); + pvpMatchStatistics.Write(); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetTypeID(), GetBracketId(), GetArenaType()); @@ -798,11 +802,12 @@ void Battleground::EndBattleground(uint32 winner) BlockMovement(player); - player->SendDirectMessage(&pvpLogData); + player->SendDirectMessage(pvpMatchStatistics.GetRawPacket()); + + WorldPackets::Battleground::BattlefieldStatusActive battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusActive(&battlefieldStatus, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), bgQueueTypeId); + player->SendDirectMessage(battlefieldStatus.Write()); - WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType(), player->GetBGTeam()); - player->SendDirectMessage(&data); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, player->GetMapId()); } } @@ -886,9 +891,9 @@ void Battleground::RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool Sen if (SendPacket) { - WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0, 0); - player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusNone battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusNone(&battlefieldStatus, player->GetBattlegroundQueueIndex(bgQueueTypeId)); + player->SendDirectMessage(battlefieldStatus.Write()); } // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg @@ -910,9 +915,9 @@ void Battleground::RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool Sen sBattlegroundMgr->ScheduleQueueUpdate(0, bgQueueTypeId); } // Let others know - WorldPacket data; - sBattlegroundMgr->BuildPlayerLeftBattlegroundPacket(&data, guid); - SendPacketToTeam(team, &data, player, false); + WorldPackets::Battleground::BattlegroundPlayerLeft playerLeft; + playerLeft.Guid = guid; + SendPacketToTeam(team, playerLeft.Write(), player, false); } if (player) @@ -1001,9 +1006,9 @@ void Battleground::AddPlayer(Player* player) if (!isInBattleground) UpdatePlayersCountByTeam(team, false); // +1 player - WorldPacket data; - sBattlegroundMgr->BuildPlayerJoinedBattlegroundPacket(&data, player); - SendPacketToTeam(team, &data, player, false); + WorldPackets::Battleground::BattlegroundPlayerJoined playerJoined; + playerJoined.Guid = player->GetGUID(); + SendPacketToTeam(team, playerJoined.Write(), player, false); player->RemoveAurasByType(SPELL_AURA_MOUNTED); @@ -1200,33 +1205,33 @@ bool Battleground::HasFreeSlots() const return GetPlayersSize() < GetMaxPlayers(); } -void Battleground::BuildPvPLogDataPacket(WorldPacket& data) +void Battleground::BuildPvPLogDataPacket(WorldPackets::Battleground::PVPMatchStatistics& pvpLogData) { - uint8 type = (isArena() ? 1 : 0); - - data.Initialize(MSG_PVP_LOG_DATA, 1 + 1 + 4 + 40 * GetPlayerScoresSize()); - data << uint8(type); // type (battleground = 0 / arena = 1) - - if (type) // arena + if (isArena()) { - for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i) - _arenaTeamScores[i].BuildRatingInfoBlock(data); + WorldPackets::Battleground::PVPLogData_Arena& arena = pvpLogData.Arena.emplace(); for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i) - _arenaTeamScores[i].BuildTeamInfoBlock(data); + { + ArenaTeamScore const& score = _arenaTeamScores[i]; + + uint32 ratingLost = std::abs(std::min(score.RatingChange, 0)); + uint32 ratingWon = std::max(score.RatingChange, 0); + + // should be old rating, new rating, and client will calculate rating change itself + arena.Ratings.Prematch[i] = ratingLost; + arena.Ratings.Postmatch[i] = ratingWon; + arena.Ratings.PrematchMMR[i] = score.MatchmakerRating; + + arena.TeamName[i] = score.TeamName; + } } if (GetStatus() == STATUS_WAIT_LEAVE) - { - data << uint8(1); // bg ended - data << uint8(GetWinner()); // who win - } - else - data << uint8(0); // bg not ended + pvpLogData.Winner = GetWinner(); - data << uint32(GetPlayerScoresSize()); - for (auto const& score : PlayerScores) - score.second->AppendToPacket(data); + for (auto const& [_, score] : PlayerScores) + score->AppendToPacket(pvpLogData.Players.emplace_back()); } bool Battleground::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) @@ -1729,16 +1734,17 @@ void Battleground::PlayerAddedToBGCheckIfBGIsRunning(Player* player) if (GetStatus() != STATUS_WAIT_LEAVE) return; - WorldPacket data; BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetTypeID(), GetBracketId(), GetArenaType()); BlockMovement(player); - BuildPvPLogDataPacket(data); - player->SendDirectMessage(&data); + WorldPackets::Battleground::PVPMatchStatistics pvpMatchStatistics; + BuildPvPLogDataPacket(pvpMatchStatistics); + player->SendDirectMessage(pvpMatchStatistics.Write()); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetBGTeam()); - player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusActive battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusActive(&battlefieldStatus, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), bgQueueTypeId); + player->SendDirectMessage(battlefieldStatus.Write()); } uint32 Battleground::GetAlivePlayersCountByTeam(uint32 Team) const diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 814c359da317a..e22e749aae687 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -29,6 +29,10 @@ namespace WorldPackets { + namespace Battleground + { + class PVPMatchStatistics; + } namespace WorldState { class InitWorldStates; @@ -399,7 +403,7 @@ class TC_GAME_API Battleground Group* GetBgRaid(uint32 TeamID) const { return TeamID == ALLIANCE ? m_BgRaids[TEAM_ALLIANCE] : m_BgRaids[TEAM_HORDE]; } void SetBgRaid(uint32 TeamID, Group* bg_raid); - void BuildPvPLogDataPacket(WorldPacket& data); + void BuildPvPLogDataPacket(WorldPackets::Battleground::PVPMatchStatistics& pvpLogData); virtual bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true); static TeamId GetTeamIndexByTeamId(uint32 Team) { return Team == ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE; } diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index 5659e75fe0437..9dc3abf8328cc 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -28,6 +28,7 @@ #include "BattlegroundDS.h" #include "BattlegroundRV.h" #include "BattlegroundIC.h" +#include "BattlegroundPackets.h" #include "Common.h" #include "Containers.h" #include "Chat.h" @@ -169,77 +170,64 @@ void BattlegroundMgr::Update(uint32 diff) } } -void BattlegroundMgr::BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype, uint32 arenaFaction) +void BattlegroundMgr::BuildBattlegroundStatusHeader(WorldPackets::Battleground::BattlefieldStatusHeader* header, Battleground const* bg, uint32 queueSlot, BattlegroundQueueTypeId queueId) { - // we can be in 2 queues in same time... + header->QueueSlot = queueSlot; + header->QueueID = queueId.GetPacked(); + header->RangeMin = bg->GetMinLevel(); + header->RangeMax = bg->GetMaxLevel(); + header->InstanceID = bg->GetClientInstanceID(); + header->RegisteredMatch = bg->isRated(); +} - if (StatusID == 0 || !bg) - { - data->Initialize(SMSG_BATTLEFIELD_STATUS, 4+8); - *data << uint32(QueueSlot); // queue id (0...1) - *data << uint64(0); - return; - } +void BattlegroundMgr::BuildBattlegroundStatusNone(WorldPackets::Battleground::BattlefieldStatusNone* battlefieldStatus, uint32 queueSlot) +{ + battlefieldStatus->QueueSlot = queueSlot; +} + +void BattlegroundMgr::BuildBattlegroundStatusNeedConfirmation(WorldPackets::Battleground::BattlefieldStatusNeedConfirmation* battlefieldStatus, Battleground const* bg, uint32 queueSlot, uint32 timeout, BattlegroundQueueTypeId queueId) +{ + BuildBattlegroundStatusHeader(&battlefieldStatus->Hdr, bg, queueSlot, queueId); + battlefieldStatus->Mapid = bg->GetMapId(); + battlefieldStatus->Timeout = timeout; +} - data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+8+1+1+4+1+4+4+4)); - *data << uint32(QueueSlot); // queue id (0...1) - player can be in 2 queues in time - // The following segment is read as uint64 in client but can be appended as their original type. - *data << uint8(arenatype); - TC_LOG_DEBUG("network", "BattlegroundMgr::BuildBattlegroundStatusPacket: arenatype = {} for bg instanceID {}, TypeID {}.", arenatype, bg->GetClientInstanceID(), bg->GetTypeID()); - *data << uint8(bg->GetBracketId()); - *data << uint32(bg->GetTypeID()); - *data << uint16(0x1F90); - // End of uint64 segment, decomposed this way for simplicity - *data << uint8(bg->GetMinLevel()); - *data << uint8(bg->GetMaxLevel()); - *data << uint32(bg->GetClientInstanceID()); - // alliance/horde for BG and skirmish/rated for Arenas - // following displays the minimap-icon 0 = faction icon 1 = arenaicon - *data << uint8(bg->isRated()); // 1 for rated match, 0 for bg or non rated match - - *data << uint32(StatusID); // status - switch (StatusID) +void BattlegroundMgr::BuildBattlegroundStatusActive(WorldPackets::Battleground::BattlefieldStatusActive* battlefieldStatus, Battleground const* bg, Player const* player, uint32 queueSlot, BattlegroundQueueTypeId queueId) +{ + BuildBattlegroundStatusHeader(&battlefieldStatus->Hdr, bg, queueSlot, queueId); + battlefieldStatus->ShutdownTimer = bg->GetEndTime(); + battlefieldStatus->ArenaFaction = player->GetBGTeam() == HORDE ? PVP_TEAM_HORDE : PVP_TEAM_ALLIANCE; + battlefieldStatus->StartTimer = bg->GetStartTime(); + battlefieldStatus->Mapid = bg->GetMapId(); + if (bg->IsRandom()) { - case STATUS_WAIT_QUEUE: // status_in_queue - *data << uint32(Time1); // average wait time, milliseconds - *data << uint32(Time2); // time in queue, updated every minute!, milliseconds - break; - case STATUS_WAIT_JOIN: // status_invite - *data << uint32(bg->GetMapId()); // map id - *data << uint64(0); // 3.3.5, unknown - *data << uint32(Time1); // time to remove from queue, milliseconds - break; - case STATUS_IN_PROGRESS: // status_in_progress - *data << uint32(bg->GetMapId()); // map id - *data << uint64(0); // 3.3.5, unknown - *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds - *data << uint32(Time2); // time from bg start, milliseconds - *data << uint8(arenaFaction == ALLIANCE ? 1 : 0); // arenafaction (0 for horde, 1 for alliance) - break; - default: - TC_LOG_ERROR("bg.battleground", "Unknown BG status!"); - break; + BattlegroundTemplate const* realTemplate = sBattlegroundMgr->GetBattlegroundTemplateByTypeId(bg->GetTypeID(true)); + if (PvPDifficultyEntry const* realBracket = GetBattlegroundBracketByLevel(realTemplate->MapIDs.front(), DEFAULT_MAX_LEVEL)) + battlefieldStatus->RandomQueueID = BattlegroundQueueTypeId{ + .BattlemasterListId = uint16(realTemplate->Id), + .BracketId = uint8(realBracket->GetBracketId()), + .TeamSize = 0 + }.GetPacked(); } } -void BattlegroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result) +void BattlegroundMgr::BuildBattlegroundStatusQueued(WorldPackets::Battleground::BattlefieldStatusQueued* battlefieldStatus, Battleground const* bg, uint32 queueSlot, uint32 joinTime, BattlegroundQueueTypeId queueId, uint32 avgWaitTime) { - data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4); - *data << int32(result); - if (result == ERR_BATTLEGROUND_JOIN_TIMED_OUT || result == ERR_BATTLEGROUND_JOIN_FAILED) - *data << uint64(0); // player guid + BuildBattlegroundStatusHeader(&battlefieldStatus->Hdr, bg, queueSlot, queueId); + battlefieldStatus->AverageWaitTime = avgWaitTime; + battlefieldStatus->WaitTime = GetMSTimeDiffToNow(joinTime); } -void BattlegroundMgr::BuildPlayerLeftBattlegroundPacket(WorldPacket* data, ObjectGuid guid) +void BattlegroundMgr::BuildBattlegroundStatusFailed(WorldPackets::Battleground::BattlefieldStatusFailed* battlefieldStatus, GroupJoinBattlegroundResult result, ObjectGuid const* errorGuid /*= nullptr*/) { - data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8); - *data << uint64(guid); + battlefieldStatus->Reason = result; + if (errorGuid && (result == ERR_BATTLEGROUND_NOT_IN_BATTLEGROUND || result == ERR_BATTLEGROUND_JOIN_TIMED_OUT)) + battlefieldStatus->ClientID = *errorGuid; } -void BattlegroundMgr::BuildPlayerJoinedBattlegroundPacket(WorldPacket* data, Player* player) +void BattlegroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPackets::Battleground::GroupJoinedBattleground* groupJoinedBattleground, BattlegroundTypeId bgTypeId) { - data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8); - *data << uint64(player->GetGUID()); + groupJoinedBattleground->Reason = bgTypeId; } Battleground* BattlegroundMgr::GetBattlegroundThroughClientInstance(uint32 instanceId, BattlegroundTypeId bgTypeId) @@ -622,7 +610,7 @@ void BattlegroundMgr::InitAutomaticArenaPointDistribution() TC_LOG_DEBUG("bg.battleground", "Automatic Arena Point Distribution initialized."); } -void BattlegroundMgr::BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid guid, Player* player, BattlegroundTypeId bgTypeId, uint8 fromWhere) +void BattlegroundMgr::SendBattlegroundList(Player* player, ObjectGuid const& guid, BattlegroundTypeId bgTypeId) { if (!player) return; @@ -634,56 +622,34 @@ void BattlegroundMgr::BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid winner_kills = Trinity::Honor::hk_honor_at_level(player->GetLevel(), float(winner_kills)); loser_kills = Trinity::Honor::hk_honor_at_level(player->GetLevel(), float(loser_kills)); - data->Initialize(SMSG_BATTLEFIELD_LIST); - *data << uint64(guid); // battlemaster guid - *data << uint8(fromWhere); // from where you joined - *data << uint32(bgTypeId); // battleground id - *data << uint8(0); // unk - *data << uint8(0); // unk - - // Rewards - *data << uint8(player->GetRandomWinner()); // 3.3.3 hasWin - *data << uint32(winner_kills); // 3.3.3 winHonor - *data << uint32(winner_arena); // 3.3.3 winArena - *data << uint32(loser_kills); // 3.3.3 lossHonor + WorldPackets::Battleground::BattlefieldList battlefieldList; + battlefieldList.BattlemasterGuid = guid; + battlefieldList.PvpAnywhere = guid.IsEmpty(); + battlefieldList.BattlemasterListID = bgTypeId; + battlefieldList.MinLevel = 0; + battlefieldList.MaxLevel = 0; - uint8 isRandom = bgTypeId == BATTLEGROUND_RB; + battlefieldList.HasHolidayWinToday = player->GetRandomWinner(); + battlefieldList.HolidayWinHonorCurrencyBonus = winner_kills; + battlefieldList.HolidayFirstWinArenaCurrencyBonus = winner_arena; + battlefieldList.HolidayLossHonorCurrencyBonus = loser_kills; - *data << uint8(isRandom); // 3.3.3 isRandom - if (isRandom) - { - // Rewards (random) - *data << uint8(player->GetRandomWinner()); // 3.3.3 hasWin_Random - *data << uint32(winner_kills); // 3.3.3 winHonor_Random - *data << uint32(winner_arena); // 3.3.3 winArena_Random - *data << uint32(loser_kills); // 3.3.3 lossHonor_Random - } + battlefieldList.HasRandomWinToday = player->GetRandomWinner(); + battlefieldList.RandomWinHonorCurrencyBonus = winner_kills; + battlefieldList.RandomFirstWinArenaCurrencyBonus = winner_arena; + battlefieldList.RandomLossHonorCurrencyBonus = loser_kills; - if (bgTypeId == BATTLEGROUND_AA) // arena - *data << uint32(0); // unk (count?) - else // battleground + if (bgTypeId != BATTLEGROUND_AA) { - size_t count_pos = data->wpos(); - *data << uint32(0); // number of bg instances - - BattlegroundDataContainer::iterator it = bgDataStore.find(bgTypeId); - if (it != bgDataStore.end()) + if (BattlegroundData const* battlegrounds = Trinity::Containers::MapGetValuePtr(bgDataStore, bgTypeId)) { // expected bracket entry - if (PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(it->second.m_Battlegrounds.begin()->second->GetMapId(), player->GetLevel())) - { - uint32 count = 0; - BattlegroundBracketId bracketId = bracketEntry->GetBracketId(); - BattlegroundClientIdsContainer& clientIds = it->second.m_ClientBattlegroundIds[bracketId]; - for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end(); ++itr) - { - *data << uint32(*itr); - ++count; - } - data->put(count_pos, count); - } + if (PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(battlegrounds->m_Battlegrounds.begin()->second->GetMapId(), player->GetLevel())) + battlefieldList.Battlefields = &battlegrounds->m_ClientBattlegroundIds[bracketEntry->GetBracketId()]; } } + + player->SendDirectMessage(battlefieldList.Write()); } void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, BattlegroundTypeId bgTypeId) @@ -705,12 +671,10 @@ void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, Batt void BattlegroundMgr::SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid guid) { - WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12); - uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds - if (time_ == uint32(-1)) - time_ = 0; - data << guid << time_; - player->SendDirectMessage(&data); + WorldPackets::Battleground::AreaSpiritHealerTime areaSpiritHealerTime; + areaSpiritHealerTime.HealerGuid = guid; + areaSpiritHealerTime.TimeLeft = std::max(30000 - int32(bg->GetLastResurrectTime()), 0); + player->SendDirectMessage(areaSpiritHealerTime.Write()); } bool BattlegroundMgr::IsArenaType(BattlegroundTypeId bgTypeId) @@ -723,6 +687,11 @@ bool BattlegroundMgr::IsArenaType(BattlegroundTypeId bgTypeId) || bgTypeId == BATTLEGROUND_RL; } +bool BattlegroundMgr::IsRandomBattleground(uint32 battlemasterListId) +{ + return battlemasterListId == BATTLEGROUND_RB; +} + BattlegroundQueueTypeId BattlegroundMgr::BGQueueTypeId(BattlegroundTypeId bgTypeId, uint8 bracketId, uint8 arenaType) { return { .BattlemasterListId = uint16(bgTypeId), .BracketId = bracketId, .TeamSize = arenaType }; diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 4b3ab9f03c218..d32366f90c108 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -63,6 +63,20 @@ struct BattlegroundTemplate bool IsArena() const; }; +namespace WorldPackets +{ + namespace Battleground + { + struct BattlefieldStatusHeader; + class BattlefieldStatusNone; + class BattlefieldStatusNeedConfirmation; + class BattlefieldStatusActive; + class BattlefieldStatusQueued; + class GroupJoinedBattleground; + using BattlefieldStatusFailed = GroupJoinedBattleground; + } +} + class TC_GAME_API BattlegroundMgr { private: @@ -80,11 +94,15 @@ class TC_GAME_API BattlegroundMgr void Update(uint32 diff); /* Packet Building */ - void BuildPlayerJoinedBattlegroundPacket(WorldPacket* data, Player* player); - void BuildPlayerLeftBattlegroundPacket(WorldPacket* data, ObjectGuid guid); - void BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid guid, Player* player, BattlegroundTypeId bgTypeId, uint8 fromWhere); - void BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result); - void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType, uint32 arenaFaction); + static void BuildBattlegroundStatusHeader(WorldPackets::Battleground::BattlefieldStatusHeader* header, Battleground const* bg, uint32 queueSlot, BattlegroundQueueTypeId queueId); + static void BuildBattlegroundStatusNone(WorldPackets::Battleground::BattlefieldStatusNone* battlefieldStatus, uint32 queueSlot); + static void BuildBattlegroundStatusNeedConfirmation(WorldPackets::Battleground::BattlefieldStatusNeedConfirmation* battlefieldStatus, Battleground const* bg, uint32 queueSlot, uint32 timeout, BattlegroundQueueTypeId queueId); + static void BuildBattlegroundStatusActive(WorldPackets::Battleground::BattlefieldStatusActive* battlefieldStatus, Battleground const* bg, Player const* player, uint32 queueSlot, BattlegroundQueueTypeId queueId); + static void BuildBattlegroundStatusQueued(WorldPackets::Battleground::BattlefieldStatusQueued* battlefieldStatus, Battleground const* bg, uint32 queueSlot, uint32 joinTime, BattlegroundQueueTypeId queueId, uint32 avgWaitTime); + static void BuildBattlegroundStatusFailed(WorldPackets::Battleground::BattlefieldStatusFailed* battlefieldStatus, GroupJoinBattlegroundResult result, ObjectGuid const* errorGuid = nullptr); + static void BuildGroupJoinedBattlegroundPacket(WorldPackets::Battleground::GroupJoinedBattleground* groupJoinedBattleground, BattlegroundTypeId bgTypeId); + + void SendBattlegroundList(Player* player, ObjectGuid const& guid, BattlegroundTypeId bgTypeId); void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid guid); /* Battlegrounds */ @@ -118,6 +136,7 @@ class TC_GAME_API BattlegroundMgr bool isArenaTesting() const { return m_ArenaTesting; } bool isTesting() const { return m_Testing; } + static bool IsRandomBattleground(uint32 battlemasterListId); static BattlegroundQueueTypeId BGQueueTypeId(BattlegroundTypeId bgTypeId, uint8 bracketId, uint8 arenaType); static HolidayIds BGTypeToWeekendHolidayId(BattlegroundTypeId bgTypeId); diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp index 4807b67b2be6c..8ba8a15201237 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp +++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp @@ -19,6 +19,7 @@ #include "ArenaTeam.h" #include "ArenaTeamMgr.h" #include "BattlegroundMgr.h" +#include "BattlegroundPackets.h" #include "Chat.h" #include "DatabaseEnv.h" #include "DBCStores.h" @@ -381,9 +382,10 @@ void BattlegroundQueue::RemovePlayer(ObjectGuid guid, bool decreaseInvitedCount) plr2->RemoveBattlegroundQueueId(m_queueId); // must be called this way, because if you move this call to // queue->removeplayer, it causes bugs - WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, nullptr, queueSlot, STATUS_NONE, 0, 0, 0, 0); - plr2->SendDirectMessage(&data); + + WorldPackets::Battleground::BattlefieldStatusNone battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusNone(&battlefieldStatus, queueSlot); + plr2->SendDirectMessage(battlefieldStatus.Write()); } // then actually delete, this may delete the group as well! RemovePlayer(group->Players.begin()->first, decreaseInvitedCount); @@ -465,9 +467,9 @@ bool BattlegroundQueue::InviteGroupToBG(GroupQueueInfo* ginfo, Battleground* bg, TC_LOG_DEBUG("bg.battleground", "Battleground: invited player {} {} to BG instance {} queueindex {} bgtype {}", player->GetName(), player->GetGUID().ToString(), bg->GetInstanceID(), queueSlot, bg->GetTypeID()); - // send status packet - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, m_queueId.TeamSize, 0); - player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusNeedConfirmation battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusNeedConfirmation(&battlefieldStatus, bg, queueSlot, INVITE_ACCEPT_WAIT_TIME, bgQueueTypeId); + player->SendDirectMessage(battlefieldStatus.Write()); } return true; } @@ -1020,10 +1022,9 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) BattlegroundQueue &bgQueue = sBattlegroundMgr->GetBattlegroundQueue(m_QueueId); if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime)) { - WorldPacket data; - //we must send remaining time in queue - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, m_QueueId.TeamSize, 0); - player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusNeedConfirmation battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusNeedConfirmation(&battlefieldStatus, bg, queueSlot, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, m_QueueId); + player->SendDirectMessage(battlefieldStatus.Write()); } } return true; //event will be deleted @@ -1079,9 +1080,9 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) if (bg && bg->isBattleground() && bg->GetStatus() != STATUS_WAIT_LEAVE) sBattlegroundMgr->ScheduleQueueUpdate(0, m_BgQueueTypeId); - WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0); - player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusNone battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusNone(&battlefieldStatus, queueSlot); + player->SendDirectMessage(battlefieldStatus.Write()); } } diff --git a/src/server/game/Battlegrounds/BattlegroundScore.h b/src/server/game/Battlegrounds/BattlegroundScore.h index f4c19320678e3..999e8c4133d46 100644 --- a/src/server/game/Battlegrounds/BattlegroundScore.h +++ b/src/server/game/Battlegrounds/BattlegroundScore.h @@ -22,6 +22,11 @@ #include "ObjectGuid.h" #include "SharedDefines.h" +namespace WorldPackets::Battleground +{ +struct PVPLogData_Player; +} + class WorldPacket; enum ScoreType @@ -92,8 +97,8 @@ struct BattlegroundScore } } - virtual void AppendToPacket(WorldPacket& data); - virtual void BuildObjectivesBlock(WorldPacket& /*data*/) = 0; + virtual void AppendToPacket(WorldPackets::Battleground::PVPLogData_Player& playerData); + virtual void BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) = 0; // For Logging purpose virtual std::string ToString() const { return ""; } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index 2f0320c55c3b3..c9353d29e3c94 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -17,6 +17,7 @@ #include "BattlegroundAB.h" #include "BattlegroundMgr.h" +#include "BattlegroundPackets.h" #include "Creature.h" #include "DBCStores.h" #include "GameObject.h" @@ -25,15 +26,12 @@ #include "Player.h" #include "Random.h" #include "Util.h" -#include "WorldPacket.h" #include "WorldSession.h" #include "WorldStatePackets.h" -void BattlegroundABScore::BuildObjectivesBlock(WorldPacket& data) +void BattlegroundABScore::BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) { - data << uint32(2); - data << uint32(BasesAssaulted); - data << uint32(BasesDefended); + playerData.Stats = { BasesAssaulted, BasesDefended }; } BattlegroundAB::BattlegroundAB() diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h index c30958d9c192f..a57c38e435f8a 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h @@ -288,10 +288,10 @@ struct BattlegroundABScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final override; + void BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) override; - uint32 GetAttr1() const final override { return BasesAssaulted; } - uint32 GetAttr2() const final override { return BasesDefended; } + uint32 GetAttr1() const override { return BasesAssaulted; } + uint32 GetAttr2() const override { return BasesDefended; } uint32 BasesAssaulted; uint32 BasesDefended; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index 8d258d34075da..6f272a874d452 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -16,6 +16,7 @@ */ #include "BattlegroundAV.h" +#include "BattlegroundPackets.h" #include "Creature.h" #include "CreatureAI.h" #include "DBCStores.h" @@ -27,14 +28,9 @@ #include "WorldSession.h" #include "WorldStatePackets.h" -void BattlegroundAVScore::BuildObjectivesBlock(WorldPacket& data) +void BattlegroundAVScore::BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) { - data << uint32(5); // Objectives Count - data << uint32(GraveyardsAssaulted); - data << uint32(GraveyardsDefended); - data << uint32(TowersAssaulted); - data << uint32(TowersDefended); - data << uint32(MinesCaptured); + playerData.Stats = { GraveyardsAssaulted, GraveyardsDefended, TowersAssaulted, TowersDefended, MinesCaptured }; } BattlegroundAV::BattlegroundAV() diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index 249cb0dfb736b..8e40f65a6a601 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -1597,13 +1597,13 @@ struct BattlegroundAVScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final override; + void BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) override; - uint32 GetAttr1() const final override { return GraveyardsAssaulted; } - uint32 GetAttr2() const final override { return GraveyardsDefended; } - uint32 GetAttr3() const final override { return TowersAssaulted; } - uint32 GetAttr4() const final override { return TowersDefended; } - uint32 GetAttr5() const final override { return MinesCaptured; } + uint32 GetAttr1() const override { return GraveyardsAssaulted; } + uint32 GetAttr2() const override { return GraveyardsDefended; } + uint32 GetAttr3() const override { return TowersAssaulted; } + uint32 GetAttr4() const override { return TowersDefended; } + uint32 GetAttr5() const override { return MinesCaptured; } uint32 GraveyardsAssaulted; uint32 GraveyardsDefended; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index f230ec277a89f..a9e55f5cc3390 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -17,6 +17,7 @@ #include "BattlegroundEY.h" #include "BattlegroundMgr.h" +#include "BattlegroundPackets.h" #include "Creature.h" #include "DBCStores.h" #include "GameObject.h" @@ -26,7 +27,6 @@ #include "Player.h" #include "Random.h" #include "Util.h" -#include "WorldPacket.h" #include "WorldStatePackets.h" // these variables aren't used outside of this file, so declare them only here @@ -36,10 +36,9 @@ uint32 BG_EY_HonorScoreTicks[BG_HONOR_MODE_NUM] = 160 // holiday }; -void BattlegroundEYScore::BuildObjectivesBlock(WorldPacket& data) +void BattlegroundEYScore::BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) { - data << uint32(1); // Objectives Count - data << uint32(FlagCaptures); + playerData.Stats = { FlagCaptures }; } BattlegroundEY::BattlegroundEY() diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h index e45a09a7a137d..81b3d897cab28 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h @@ -370,9 +370,9 @@ struct BattlegroundEYScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final override; + void BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) override; - uint32 GetAttr1() const final override { return FlagCaptures; } + uint32 GetAttr1() const override { return FlagCaptures; } uint32 FlagCaptures; }; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp index 15cdbe8eaaca3..cf71d03db3ec4 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -16,6 +16,7 @@ */ #include "BattlegroundIC.h" +#include "BattlegroundPackets.h" #include "GameObject.h" #include "Log.h" #include "Map.h" @@ -23,14 +24,11 @@ #include "ScriptedCreature.h" #include "Transport.h" #include "Vehicle.h" -#include "WorldPacket.h" #include "WorldStatePackets.h" -void BattlegroundICScore::BuildObjectivesBlock(WorldPacket& data) +void BattlegroundICScore::BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) { - data << uint32(2); // Objectives Count - data << uint32(BasesAssaulted); - data << uint32(BasesDefended); + playerData.Stats = { BasesAssaulted, BasesDefended }; } BattlegroundIC::BattlegroundIC() diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h index c2192e28c533b..e70d55558172d 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h @@ -930,10 +930,10 @@ struct BattlegroundICScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final override; + void BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) override; - uint32 GetAttr1() const final override { return BasesAssaulted; } - uint32 GetAttr2() const final override { return BasesDefended; } + uint32 GetAttr1() const override { return BasesAssaulted; } + uint32 GetAttr2() const override { return BasesDefended; } uint32 BasesAssaulted; uint32 BasesDefended; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp index 3477a18ebf7f1..3de916ca0e21c 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp @@ -16,6 +16,7 @@ */ #include "BattlegroundSA.h" +#include "BattlegroundPackets.h" #include "DBCStores.h" #include "GameObject.h" #include "GameTime.h" @@ -26,14 +27,11 @@ #include "Player.h" #include "ScriptedCreature.h" #include "UpdateData.h" -#include "WorldPacket.h" #include "WorldStatePackets.h" -void BattlegroundSAScore::BuildObjectivesBlock(WorldPacket& data) +void BattlegroundSAScore::BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) { - data << uint32(2); // Objectives Count - data << uint32(DemolishersDestroyed); - data << uint32(GatesDestroyed); + playerData.Stats = { DemolishersDestroyed, GatesDestroyed }; } BattlegroundSA::BattlegroundSA() diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h index 1f2c2e53af09e..17b5b9dd04143 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h @@ -539,10 +539,10 @@ struct BattlegroundSAScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final override; + void BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) override; - uint32 GetAttr1() const final override { return DemolishersDestroyed; } - uint32 GetAttr2() const final override { return GatesDestroyed; } + uint32 GetAttr1() const override { return DemolishersDestroyed; } + uint32 GetAttr2() const override { return GatesDestroyed; } uint32 DemolishersDestroyed; uint32 GatesDestroyed; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index 7c00dd599922e..90d2d5ef106a5 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -17,6 +17,7 @@ #include "BattlegroundWS.h" #include "BattlegroundMgr.h" +#include "BattlegroundPackets.h" #include "DBCStores.h" #include "GameObject.h" #include "Log.h" @@ -71,11 +72,9 @@ BattlegroundWS::BattlegroundWS() _minutesElapsed = 0; } -void BattlegroundWGScore::BuildObjectivesBlock(WorldPacket& data) +void BattlegroundWGScore::BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) { - data << uint32(2); // Objectives Count - data << uint32(FlagCaptures); - data << uint32(FlagReturns); + playerData.Stats = { FlagCaptures, FlagReturns }; } BattlegroundWS::~BattlegroundWS() { } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h index aa120ab8f3ade..1d034b30cbf0e 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h @@ -186,10 +186,10 @@ struct BattlegroundWGScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final override; + void BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player& playerData) override; - uint32 GetAttr1() const final override { return FlagCaptures; } - uint32 GetAttr2() const final override { return FlagReturns; } + uint32 GetAttr1() const override { return FlagCaptures; } + uint32 GetAttr2() const override { return FlagReturns; } uint32 FlagCaptures; uint32 FlagReturns; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index df73ba3c1d797..060f3e25e6124 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -233,19 +233,6 @@ void Object::DestroyForPlayer(Player* target, bool onDeath) const { ASSERT(target); - if (IsUnit()) - { - if (Battleground* bg = target->GetBattleground()) - { - if (bg->isArena()) - { - WorldPacket data(SMSG_ARENA_UNIT_DESTROYED, 8); - data << uint64(GetGUID()); - target->SendDirectMessage(&data); - } - } - } - WorldPacket data(SMSG_DESTROY_OBJECT, 8 + 1); data << uint64(GetGUID()); //! If the following bool is true, the client will call "void CGUnit_C::OnDeath()" for this object. diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 7892f4e0ae52e..497c803a8be8c 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -25,6 +25,7 @@ #include "BattlefieldMgr.h" #include "Battleground.h" #include "BattlegroundMgr.h" +#include "BattlegroundPackets.h" #include "BattlegroundScore.h" #include "CellImpl.h" #include "Channel.h" @@ -14369,7 +14370,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men return; } - GetSession()->SendBattleGroundList(guid, bgTypeId); + sBattlegroundMgr->SendBattlegroundList(this, guid, bgTypeId); break; } } @@ -22191,23 +22192,33 @@ bool Player::CanReportAfkDueToLimit() ///This player has been blamed to be inactive in a battleground void Player::ReportedAfkBy(Player* reporter) { + WorldPackets::Battleground::ReportPvPPlayerAFKResult reportAfkResult; + reportAfkResult.Offender = GetGUID(); Battleground* bg = GetBattleground(); // Battleground also must be in progress! if (!bg || bg != reporter->GetBattleground() || GetTeam() != reporter->GetTeam() || bg->GetStatus() != STATUS_IN_PROGRESS) + { + reporter->SendDirectMessage(reportAfkResult.Write()); return; + } // check if player has 'Idle' or 'Inactive' debuff - if (m_bgData.bgAfkReporter.find(reporter->GetGUID().GetCounter()) == m_bgData.bgAfkReporter.end() && !HasAura(43680) && !HasAura(43681) && reporter->CanReportAfkDueToLimit()) + if (m_bgData.bgAfkReporter.find(reporter->GetGUID()) == m_bgData.bgAfkReporter.end() && !HasAura(43680) && !HasAura(43681) && reporter->CanReportAfkDueToLimit()) { - m_bgData.bgAfkReporter.insert(reporter->GetGUID().GetCounter()); + m_bgData.bgAfkReporter.insert(reporter->GetGUID()); // by default 3 players have to complain to apply debuff if (m_bgData.bgAfkReporter.size() >= sWorld->getIntConfig(CONFIG_BATTLEGROUND_REPORT_AFK)) { // cast 'Idle' spell CastSpell(this, 43680, true); m_bgData.bgAfkReporter.clear(); + reportAfkResult.NumBlackMarksOnOffender = m_bgData.bgAfkReporter.size(); + reportAfkResult.NumPlayersIHaveReported = reporter->m_bgData.bgAfkReportedCount; + reportAfkResult.Result = WorldPackets::Battleground::ReportPvPPlayerAFKResult::PVP_REPORT_AFK_SUCCESS; } } + + reporter->SendDirectMessage(reportAfkResult.Write()); } WorldLocation Player::GetStartPosition() const diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 23915ad87cf08..cc4df35f6a9c5 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -831,7 +831,7 @@ struct BGData /// when player is teleported to BG - (it is battleground's GUID) BattlegroundTypeId bgTypeID; - std::set bgAfkReporter; + GuidSet bgAfkReporter; uint8 bgAfkReportedCount; time_t bgAfkReportedTimer; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 715b79f477d75..bac4222cf4d32 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -20,6 +20,7 @@ #include "Battlefield.h" #include "BattlefieldMgr.h" #include "Battleground.h" +#include "BattlegroundPackets.h" #include "BattlegroundScore.h" #include "CellImpl.h" #include "CharacterCache.h" @@ -13584,6 +13585,21 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player const* t data->append(fieldBuffer); } +void Unit::DestroyForPlayer(Player* target, bool onDeath) const +{ + if (Battleground* bg = target->GetBattleground()) + { + if (bg->isArena()) + { + WorldPackets::Battleground::DestroyArenaUnit destroyArenaUnit; + destroyArenaUnit.Guid = GetGUID(); + target->GetSession()->SendPacket(destroyArenaUnit.Write()); + } + } + + WorldObject::DestroyForPlayer(target, onDeath); +} + int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const { int32 val = 0; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index e549513425228..5991b268b8753 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1833,6 +1833,7 @@ class TC_GAME_API Unit : public WorldObject explicit Unit (bool isWorldObject); void BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, Player const* target) const override; + void DestroyForPlayer(Player* target, bool onDeath) const override; void _UpdateSpells(uint32 time); void _DeleteRemovedAuras(); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 135fee4c58d4c..7c17d794c0eab 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -2013,8 +2013,10 @@ void Group::UpdateLooterGuid(WorldObject* pLootedObject, bool ifneed) } } -GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 /*MaxPlayerCount*/, bool isRated, uint32 arenaSlot) +GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 /*MaxPlayerCount*/, bool isRated, uint32 arenaSlot, ObjectGuid& errorGuid) const { + errorGuid = ObjectGuid::Empty; + // check if this group is LFG group if (isLFGGroup()) return ERR_LFG_CANT_USE_BATTLEGROUND; @@ -2044,12 +2046,13 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* // check every member of the group to be able to join memberscount = 0; - for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next(), ++memberscount) + for (GroupReference const* itr = GetFirstMember(); itr != nullptr; itr = itr->next(), ++memberscount) { Player* member = itr->GetSource(); // offline member? don't let join if (!member) return ERR_BATTLEGROUND_JOIN_FAILED; + errorGuid = member->GetGUID(); // rbac permissions if (!member->CanJoinToBattleground(bgOrTemplate)) return ERR_BATTLEGROUND_JOIN_TIMED_OUT; @@ -2087,6 +2090,8 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* return ERR_BATTLEGROUND_JOIN_FAILED; } + errorGuid = ObjectGuid::Empty; + // only check for MinPlayerCount since MinPlayerCount == MaxPlayerCount for arenas... if (bgOrTemplate->isArena() && memberscount != MinPlayerCount) return ERR_ARENA_TEAM_PARTY_SIZE; diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index f03a2fc44faba..8c43bba530142 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -257,7 +257,7 @@ class TC_GAME_API Group void SetBattlegroundGroup(Battleground* bg); void SetBattlefieldGroup(Battlefield* bf); - GroupJoinBattlegroundResult CanJoinBattlegroundQueue(Battleground const* bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot); + GroupJoinBattlegroundResult CanJoinBattlegroundQueue(Battleground const* bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot, ObjectGuid& errorGuid) const; void ChangeMembersGroup(ObjectGuid guid, uint8 group); void SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid); diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index 658c42ef0a50a..81f3591dc9837 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -18,8 +18,11 @@ #include "WorldSession.h" #include "ArenaTeam.h" #include "ArenaTeamMgr.h" +#include "Battlefield.h" +#include "BattlefieldMgr.h" #include "Battleground.h" #include "BattlegroundMgr.h" +#include "BattlegroundPackets.h" #include "Chat.h" #include "Common.h" #include "Creature.h" @@ -30,21 +33,15 @@ #include "Group.h" #include "Language.h" #include "Log.h" +#include "NPCPackets.h" #include "Object.h" #include "ObjectAccessor.h" -#include "ObjectMgr.h" -#include "Opcodes.h" #include "Player.h" #include "World.h" -#include "WorldPacket.h" -void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket& recvData) +void WorldSession::HandleBattlemasterHelloOpcode(WorldPackets::NPC::Hello& hello) { - ObjectGuid guid; - recvData >> guid; - TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from {}", guid.ToString()); - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BATTLEMASTER); + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(hello.Unit, UNIT_NPC_FLAG_BATTLEMASTER); if (!unit) return; @@ -62,45 +59,25 @@ void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket& recvData) return; } - SendBattleGroundList(guid, bgTypeId); -} - -void WorldSession::SendBattleGroundList(ObjectGuid guid, BattlegroundTypeId bgTypeId) -{ - WorldPacket data; - sBattlegroundMgr->BuildBattlegroundListPacket(&data, guid, _player, bgTypeId, 0); - SendPacket(&data); + sBattlegroundMgr->SendBattlegroundList(_player, hello.Unit, bgTypeId); } -void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) +void WorldSession::HandleBattlemasterJoinOpcode(WorldPackets::Battleground::BattlemasterJoin& battlemasterJoin) { - ObjectGuid guid; - uint32 bgTypeId_; - uint32 instanceId; - uint8 joinAsGroup; bool isPremade = false; - Group* grp = nullptr; - - recvData >> guid; // battlemaster guid - recvData >> bgTypeId_; // battleground type id (DBC id) - recvData >> instanceId; // instance id, 0 if First Available selected - recvData >> joinAsGroup; // join as group - - if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) + if (!sBattlemasterListStore.LookupEntry(battlemasterJoin.BattlemasterListID)) { - TC_LOG_ERROR("network", "Battleground: invalid bgtype ({}) received. possible cheater? player {}", bgTypeId_, _player->GetGUID().ToString()); + TC_LOG_ERROR("network", "Battleground: invalid bgtype ({}) received. possible cheater? player {}", battlemasterJoin.BattlemasterListID, _player->GetGUID().ToString()); return; } - if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, nullptr)) + if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, battlemasterJoin.BattlemasterListID, nullptr)) { ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED); return; } - BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); - - TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from {}", guid.ToString()); + BattlegroundTypeId bgTypeId = BattlegroundTypeId(battlemasterJoin.BattlemasterListID); // ignore if player is already in BG if (_player->InBattleground()) @@ -108,8 +85,8 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) // get bg instance or bg template if instance not found Battleground* bg = nullptr; - if (instanceId) - bg = sBattlegroundMgr->GetBattlegroundThroughClientInstance(instanceId, bgTypeId); + if (battlemasterJoin.InstanceID) + bg = sBattlegroundMgr->GetBattlegroundThroughClientInstance(battlemasterJoin.InstanceID, bgTypeId); if (!bg) bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); @@ -123,55 +100,62 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) // can do this, since it's battleground, not arena BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, bracketEntry->GetBracketId(), 0); - BattlegroundQueueTypeId bgQueueTypeIdRandom = BattlegroundMgr::BGQueueTypeId(BATTLEGROUND_RB, bracketEntry->GetBracketId(), 0); - GroupJoinBattlegroundResult err; + GroupJoinBattlegroundResult err = ERR_BATTLEGROUND_NONE; + + Group const* grp = _player->GetGroup(); // check queue conditions - if (!joinAsGroup) + if (!battlemasterJoin.JoinAsGroup) { if (GetPlayer()->isUsingLfg()) { - // player is using dungeon finder or raid finder - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_LFG_CANT_USE_BATTLEGROUND); - GetPlayer()->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, ERR_LFG_CANT_USE_BATTLEGROUND); + SendPacket(battlefieldStatus.Write()); return; } // check RBAC permissions if (!_player->CanJoinToBattleground(bg)) { - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_TIMED_OUT); - GetPlayer()->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, ERR_BATTLEGROUND_JOIN_TIMED_OUT); + SendPacket(battlefieldStatus.Write()); return; } // check Deserter debuff if (_player->IsDeserter()) { - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); - _player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); + SendPacket(battlefieldStatus.Write()); return; } - if (_player->GetBattlegroundQueueIndex(bgQueueTypeIdRandom) < PLAYER_MAX_BATTLEGROUND_QUEUES) + bool isInRandomBgQueue = [&] + { + for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + if (_player->GetBattlegroundQueueTypeId(i).BattlemasterListId == BATTLEGROUND_RB) + return true; + return false; + }(); + if (!BattlegroundMgr::IsRandomBattleground(bgTypeId) && isInRandomBgQueue) { // player is already in random queue - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_RANDOM_BG); - _player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, ERR_IN_RANDOM_BG); + SendPacket(battlefieldStatus.Write()); return; } - if (_player->InBattlegroundQueue(true) && bgTypeId == BATTLEGROUND_RB) + if (_player->InBattlegroundQueue(true) && !isInRandomBgQueue && BattlegroundMgr::IsRandomBattleground(bgTypeId)) { // player is already in queue, can't start random queue - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_NON_RANDOM_BG); - _player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, ERR_IN_NON_RANDOM_BG); + SendPacket(battlefieldStatus.Write()); return; } @@ -183,9 +167,9 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) // check if has free queue slots if (!_player->HasFreeBattlegroundQueueId()) { - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_TOO_MANY_QUEUES); - _player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, ERR_BATTLEGROUND_TOO_MANY_QUEUES); + SendPacket(battlefieldStatus.Write()); return; } @@ -194,29 +178,27 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) return; BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); - GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bracketEntry, false, isPremade, 0, 0); uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo); - // already checked if queueSlot is valid, now just get it uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); - WorldPacket data; - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, 0, 0); - SendPacket(&data); + WorldPackets::Battleground::BattlefieldStatusQueued battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusQueued(&battlefieldStatus, bg, queueSlot, ginfo->JoinTime, bgQueueTypeId, avgTime); + SendPacket(battlefieldStatus.Write()); + TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue {{ BattlemasterListId: {}, BracketId: {}, TeamSize: {} }}, {}, NAME {}", bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.BracketId), uint32(bgQueueTypeId.TeamSize), _player->GetGUID().ToString(), _player->GetName()); } else { - grp = _player->GetGroup(); - // no group found, error if (!grp) return; if (grp->GetLeaderGUID() != _player->GetGUID()) return; - err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); + + ObjectGuid errorGuid; + err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0, errorGuid); isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); @@ -230,29 +212,30 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) avgTime = bgQueue.GetAverageQueueWaitTime(ginfo); } - for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next()) + for (GroupReference const* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* member = itr->GetSource(); if (!member) continue; // this should never happen - WorldPacket data; - if (err <= 0) { - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); - member->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, err, &errorGuid); + member->SendDirectMessage(battlefieldStatus.Write()); continue; } // add to queue uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, 0, 0); - member->SendDirectMessage(&data); - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); - member->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusQueued battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusQueued(&battlefieldStatus, bg, queueSlot, ginfo->JoinTime, bgQueueTypeId, avgTime); + member->SendDirectMessage(battlefieldStatus.Write()); + + WorldPackets::Battleground::GroupJoinedBattleground groupJoinedBattleground; + BattlegroundMgr::BuildGroupJoinedBattlegroundPacket(&groupJoinedBattleground, BattlegroundTypeId(err)); + member->SendDirectMessage(battlefieldStatus.Write()); TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue {{ BattlemasterListId: {}, BracketId: {}, TeamSize: {} }}, {}, NAME {}", bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.BracketId), uint32(bgQueueTypeId.TeamSize), member->GetGUID().ToString(), member->GetName()); @@ -262,61 +245,26 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) sBattlegroundMgr->ScheduleQueueUpdate(0, bgQueueTypeId); } -void WorldSession::HandleBattlegroundPlayerPositionsOpcode(WorldPacket& /*recvData*/) +void WorldSession::HandleBattlegroundPlayerPositionsOpcode(WorldPackets::Battleground::BattlegroundPlayerPositionsRequest& /*battlegroundPlayerPositionsRequest*/) { - TC_LOG_DEBUG("network", "WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message"); - Battleground* bg = _player->GetBattleground(); if (!bg) // can't be received if player not in battleground return; - uint32 flagCarrierCount = 0; - Player* allianceFlagCarrier = nullptr; - Player* hordeFlagCarrier = nullptr; - + WorldPackets::Battleground::BattlegroundPlayerPositions playerPositions; if (ObjectGuid guid = bg->GetFlagPickerGUID(TEAM_ALLIANCE)) - { - allianceFlagCarrier = ObjectAccessor::FindPlayer(guid); - if (allianceFlagCarrier) - ++flagCarrierCount; - } + if (Player* allianceFlagCarrier = ObjectAccessor::GetPlayer(*_player, guid)) + playerPositions.FlagCarriers.emplace_back(guid, allianceFlagCarrier->GetPosition()); if (ObjectGuid guid = bg->GetFlagPickerGUID(TEAM_HORDE)) - { - hordeFlagCarrier = ObjectAccessor::FindPlayer(guid); - if (hordeFlagCarrier) - ++flagCarrierCount; - } - - WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, 4 + 4 + 16 * flagCarrierCount); - // Used to send several player positions (found used in AV) - data << 0; // CGBattlefieldInfo__m_numPlayerPositions - /* - for (CGBattlefieldInfo__m_numPlayerPositions) - data << guid << posx << posy; - */ - data << flagCarrierCount; - if (allianceFlagCarrier) - { - data << uint64(allianceFlagCarrier->GetGUID()); - data << float(allianceFlagCarrier->GetPositionX()); - data << float(allianceFlagCarrier->GetPositionY()); - } - - if (hordeFlagCarrier) - { - data << uint64(hordeFlagCarrier->GetGUID()); - data << float(hordeFlagCarrier->GetPositionX()); - data << float(hordeFlagCarrier->GetPositionY()); - } + if (Player* hordeFlagCarrier = ObjectAccessor::GetPlayer(*_player, guid)) + playerPositions.FlagCarriers.emplace_back(guid, hordeFlagCarrier->GetPosition()); - SendPacket(&data); + SendPacket(playerPositions.Write()); } -void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandlePVPLogDataOpcode(WorldPackets::Battleground::PVPLogDataRequest& /*pvpLogDataRequest*/) { - TC_LOG_DEBUG("network", "WORLD: Recvd MSG_PVP_LOG_DATA Message"); - Battleground* bg = _player->GetBattleground(); if (!bg) return; @@ -325,103 +273,73 @@ void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recvData*/) if (bg->isArena()) return; - WorldPacket data; - bg->BuildPvPLogDataPacket(data); - SendPacket(&data); - - TC_LOG_DEBUG("network", "WORLD: Sent MSG_PVP_LOG_DATA Message"); + WorldPackets::Battleground::PVPMatchStatistics pvpMatchStatistics; + bg->BuildPvPLogDataPacket(pvpMatchStatistics); + SendPacket(pvpMatchStatistics.Write()); } -void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recvData) +void WorldSession::HandleBattlefieldListOpcode(WorldPackets::Battleground::BattlefieldListRequest& battlefieldList) { - TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); - - uint32 bgTypeId; - recvData >> bgTypeId; // id from DBC - - uint8 fromWhere; - recvData >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo) - - uint8 canGainXP; - recvData >> canGainXP; // players with locked xp have their own bg queue on retail - - BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); - if (!bl) + BattlemasterListEntry const* battlemasterListEntry = sBattlemasterListStore.LookupEntry(battlefieldList.ListID); + if (!battlemasterListEntry) { - TC_LOG_DEBUG("bg.battleground", "BattlegroundHandler: invalid bgtype ({}) with player (Name: {}, {}) received.", bgTypeId, _player->GetName(), _player->GetGUID().ToString()); + TC_LOG_DEBUG("bg.battleground", "BattlegroundHandler: invalid bgtype ({}) with player (Name: {}, {}) received.", battlefieldList.ListID, _player->GetName(), _player->GetGUID().ToString()); return; } - WorldPacket data; - sBattlegroundMgr->BuildBattlegroundListPacket(&data, ObjectGuid::Empty, _player, BattlegroundTypeId(bgTypeId), fromWhere); - SendPacket(&data); + sBattlegroundMgr->SendBattlegroundList(_player, ObjectGuid::Empty, BattlegroundTypeId(battlefieldList.ListID)); } -void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) +void WorldSession::HandleBattleFieldPortOpcode(WorldPackets::Battleground::BattlefieldPort& battlefieldPort) { - uint64 packedQueueId; - uint8 action; // enter battle 0x1, leave queue 0x0 - - recvData >> packedQueueId >> action; - - BattlegroundQueueTypeId bgQueueTypeId = BattlegroundQueueTypeId::FromPacked(packedQueueId); - uint8 type = bgQueueTypeId.TeamSize; - uint8 unk2 = bgQueueTypeId.BracketId; - uint32 bgTypeId_ = bgQueueTypeId.BattlemasterListId; - if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) - { - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Invalid BgType!", - GetPlayerInfo(), type, unk2, bgTypeId_, action); - return; - } - - if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) == PLAYER_MAX_BATTLEGROUND_QUEUES) + BattlegroundQueueTypeId bgQueueTypeId = BattlegroundQueueTypeId::FromPacked(battlefieldPort.QueueID); + uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); + if (queueSlot >= PLAYER_MAX_BATTLEGROUND_QUEUES) { - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Player not in queue!", - GetPlayerInfo(), type, unk2, bgTypeId_, action); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} queue {{ BattlemasterListId: {}, BracketId: {}, TeamSize: {} }}, AcceptedInvite: {}. Invalid queueSlot.", + GetPlayerInfo(), bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.BracketId), uint32(bgQueueTypeId.TeamSize), battlefieldPort.AcceptedInvite); return; } - //get GroupQueueInfo from BattlegroundQueue BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) { - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Player not in queue (No player Group Info)!", - GetPlayerInfo(), type, unk2, bgTypeId_, action); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} queue {{ BattlemasterListId: {}, BracketId: {}, TeamSize: {} }}, AcceptedInvite: {}. Player not in queue (No player Group Info)!", + GetPlayerInfo(), bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.BracketId), uint32(bgQueueTypeId.TeamSize), battlefieldPort.AcceptedInvite); return; } - // if action == 1, then instanceId is required - if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) + // if action == 1, then player must have been invited to join + if (!ginfo.IsInvitedToBGInstanceGUID && battlefieldPort.AcceptedInvite) { - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Player is not invited to any bg!", - GetPlayerInfo(), type, unk2, bgTypeId_, action); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} queue {{ BattlemasterListId: {}, BracketId: {}, TeamSize: {} }}, AcceptedInvite: {}. Player is not invited to any bg!", + GetPlayerInfo(), bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.BracketId), uint32(bgQueueTypeId.TeamSize), battlefieldPort.AcceptedInvite); return; } - BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); + BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgQueueTypeId.BattlemasterListId); Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); if (!bg) { - if (action) + if (battlefieldPort.AcceptedInvite) { - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Cant find BG with id {}!", - GetPlayerInfo(), type, unk2, bgTypeId_, action, ginfo.IsInvitedToBGInstanceGUID); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} queue {{ BattlemasterListId: {}, BracketId: {}, TeamSize: {} }}, AcceptedInvite: {}. Cant find BG with id {}!", + GetPlayerInfo(), bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.BracketId), uint32(bgQueueTypeId.TeamSize), battlefieldPort.AcceptedInvite, ginfo.IsInvitedToBGInstanceGUID); return; } bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) { - TC_LOG_ERROR("network", "BattlegroundHandler: bg_template not found for type id {}.", bgTypeId); + TC_LOG_ERROR("network", "BattlegroundHandler: BattlegroundTemplate not found for type id {}.", bgTypeId); return; } } - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}.", - GetPlayerInfo(), type, unk2, bgTypeId_, action); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} queue {{ BattlemasterListId: {}, BracketId: {}, TeamSize: {} }}, AcceptedInvite: {}.", + GetPlayerInfo(), bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.BracketId), uint32(bgQueueTypeId.TeamSize), battlefieldPort.AcceptedInvite); // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->GetLevel()); @@ -429,16 +347,16 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) return; //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it - if (action == 1 && bgQueue.GetQueueId().TeamSize == 0) + if (battlefieldPort.AcceptedInvite && bgQueue.GetQueueId().TeamSize == 0) { //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue if (_player->IsDeserter()) { //send bg command result to show nice message - WorldPacket data2; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data2, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); - _player->SendDirectMessage(&data2); - action = 0; + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); + SendPacket(battlefieldStatus.Write()); + battlefieldPort.AcceptedInvite = false; TC_LOG_DEBUG("bg.battleground", "Player {} {} has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUID().ToString()); } //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue @@ -446,12 +364,11 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) { TC_LOG_ERROR("network", "Player {} {} has level ({}) higher than maxlevel ({}) of battleground ({})! Do not port him to battleground!", _player->GetName(), _player->GetGUID().ToString(), _player->GetLevel(), bg->GetMaxLevel(), bg->GetTypeID()); - action = 0; + battlefieldPort.AcceptedInvite = false; } } - uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); - WorldPacket data; - if (action) + + if (battlefieldPort.AcceptedInvite) { // check Freeze debuff if (_player->HasAura(9454)) @@ -472,8 +389,9 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) // stop taxi flight at port _player->FinishTaxiFlight(); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), ginfo.Team); - _player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusActive battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusActive(&battlefieldStatus, bg, _player, queueSlot, bgQueueTypeId); + SendPacket(battlefieldStatus.Write()); // remove battleground queue status from BGmgr bgQueue.RemovePlayer(_player->GetGUID(), false); @@ -511,13 +429,17 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) at->SaveToDB(); } } + + WorldPackets::Battleground::BattlefieldStatusNone battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusNone(&battlefieldStatus, queueSlot); + SendPacket(battlefieldStatus.Write()); + _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0); bgQueue.RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue if (!bgQueue.GetQueueId().TeamSize) sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, bgQueueTypeId); - SendPacket(&data); + TC_LOG_DEBUG("bg.battleground", "Battleground: player {} ({}) left queue for bgtype {}, queue {{ BattlemasterListId: {}, BracketId: {}, TeamSize: {} }}.", _player->GetName(), _player->GetGUID().ToString(), bg->GetTypeID(), bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.BracketId), uint32(bgQueueTypeId.TeamSize)); @@ -534,15 +456,8 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) } } -void WorldSession::HandleBattlefieldLeaveOpcode(WorldPacket& recvData) +void WorldSession::HandleBattlefieldLeaveOpcode(WorldPackets::Battleground::BattlefieldLeave& /*battlefieldLeave*/) { - TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message"); - - recvData.read_skip(); // unk1 - recvData.read_skip(); // unk2 - recvData.read_skip(); // BattlegroundTypeId - recvData.read_skip(); // unk3 - // not allow leave battleground in combat if (_player->IsInCombat()) if (Battleground* bg = _player->GetBattleground()) @@ -552,12 +467,8 @@ void WorldSession::HandleBattlefieldLeaveOpcode(WorldPacket& recvData) _player->LeaveBattleground(); } -void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandleRequestBattlefieldStatusOpcode(WorldPackets::Battleground::RequestBattlefieldStatus& /*requestBattlefieldStatus*/) { - // empty opcode - TC_LOG_DEBUG("network", "WORLD: Battleground status"); - - WorldPacket data; // we must update all queues here Battleground* bg = nullptr; for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) @@ -567,7 +478,6 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) continue; BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgQueueTypeId.BattlemasterListId); bg = _player->GetBattleground(); - uint8 arenaType = bgQueueTypeId.TeamSize; if (bg) { BattlegroundPlayer const* bgPlayer = bg->GetBattlegroundPlayerData(_player->GetGUID()); @@ -575,8 +485,9 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) { //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena //so i must use bg pointer to get that information - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType, _player->GetBGTeam()); - SendPacket(&data); + WorldPackets::Battleground::BattlefieldStatusActive battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusActive(&battlefieldStatus, bg, _player, i, bgQueueTypeId); + SendPacket(battlefieldStatus.Write()); continue; } } @@ -592,10 +503,10 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); if (!bg) continue; - uint32 remainingTime = getMSTimeDiff(GameTime::GetGameTimeMS(), ginfo.RemoveInviteTime); - // send status invited to Battleground - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType, 0); - SendPacket(&data); + + WorldPackets::Battleground::BattlefieldStatusNeedConfirmation battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusNeedConfirmation(&battlefieldStatus, bg, i, getMSTimeDiff(GameTime::GetGameTimeMS(), ginfo.RemoveInviteTime), bgQueueTypeId); + SendPacket(battlefieldStatus.Write()); } else { @@ -609,43 +520,33 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) continue; uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo); - // send status in Battleground Queue - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, GameTime::GetGameTimeMS()), arenaType, 0); - SendPacket(&data); + WorldPackets::Battleground::BattlefieldStatusQueued battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusQueued(&battlefieldStatus, bg, i, 0, bgQueueTypeId, avgTime); + SendPacket(battlefieldStatus.Write()); } } } -void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) +void WorldSession::HandleBattlemasterJoinArena(WorldPackets::Battleground::BattlemasterJoinArena& packet) { - TC_LOG_DEBUG("network", "WORLD: CMSG_BATTLEMASTER_JOIN_ARENA"); - - ObjectGuid guid; // arena Battlemaster guid - uint8 arenaslot; // 2v2, 3v3 or 5v5 - uint8 asGroup; // asGroup - uint8 isRated; // isRated - Group* grp = nullptr; - - recvData >> guid >> arenaslot >> asGroup >> isRated; - // ignore if rated but queued solo - if (isRated && !asGroup) + if (packet.IsRated && !packet.JoinAsGroup) return; // ignore if we already in BG or BG queue if (_player->InBattleground()) return; - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BATTLEMASTER); + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.BattlemasterGuid, UNIT_NPC_FLAG_BATTLEMASTER); if (!unit) return; - uint8 arenatype = ArenaTeam::GetTypeBySlot(arenaslot); + uint8 arenatype = ArenaTeam::GetTypeBySlot(packet.TeamSizeIndex); uint32 arenaRating = 0; uint32 matchmakerRating = 0; uint32 previousOpponents = 0; - //check existance + //check existence Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(BATTLEGROUND_AA); if (!bg) { @@ -659,30 +560,29 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) return; } + BattlegroundTypeId bgTypeId = bg->GetTypeID(); PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->GetLevel()); if (!bracketEntry) return; - BattlegroundTypeId bgTypeId = bg->GetTypeID(); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, bracketEntry->GetBracketId(), arenatype); - GroupJoinBattlegroundResult err = ERR_GROUP_JOIN_BATTLEGROUND_FAIL; - - if (!asGroup) + Group* grp = _player->GetGroup(); + if (!packet.JoinAsGroup) { if (_player->isUsingLfg()) { // player is using dungeon finder or raid finder - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_LFG_CANT_USE_BATTLEGROUND); - _player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, ERR_LFG_CANT_USE_BATTLEGROUND); + SendPacket(battlefieldStatus.Write()); return; } if (!_player->CanJoinToBattleground(bg)) { - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED); - _player->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, ERR_BATTLEGROUND_JOIN_FAILED); + SendPacket(battlefieldStatus.Write()); return; } @@ -696,27 +596,26 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) } else { - grp = _player->GetGroup(); // no group found, error if (!grp) return; if (grp->GetLeaderGUID() != _player->GetGUID()) return; - err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, arenatype, arenatype, isRated != 0, arenaslot); } uint32 ateamId = 0; - if (isRated) + if (packet.IsRated) { - ateamId = _player->GetArenaTeamId(arenaslot); + ateamId = _player->GetArenaTeamId(packet.TeamSizeIndex); // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice) ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ateamId); if (!at) { - _player->GetSession()->SendNotInArenaTeamPacket(arenatype); + SendNotInArenaTeamPacket(arenatype); return; } + // get the team rating for queueing arenaRating = at->GetRating(); matchmakerRating = at->GetAverageMMR(grp); @@ -728,23 +627,25 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) previousOpponents = at->GetPreviousOpponents(); } - BattlegroundQueue &bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); - if (asGroup) + BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); + if (packet.JoinAsGroup) { uint32 avgTime = 0; + GroupQueueInfo* ginfo = nullptr; + ObjectGuid errorGuid; + GroupJoinBattlegroundResult err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, arenatype, arenatype, true, packet.TeamSizeIndex, errorGuid); if (err > 0) { - TC_LOG_DEBUG("bg.battleground", "Battleground: arena join as group start"); - if (isRated) + if (packet.IsRated) { - TC_LOG_DEBUG("bg.battleground", "Battleground: arena team id {}, leader {} queued with matchmaker rating {} for type {}", _player->GetArenaTeamId(arenaslot), _player->GetName(), matchmakerRating, arenatype); + TC_LOG_DEBUG("bg.battleground", "Battleground: arena team id {}, leader {} queued with matchmaker rating {} for type {}", _player->GetArenaTeamId(packet.TeamSizeIndex), _player->GetName(), matchmakerRating, arenatype); bg->SetRated(true); } else bg->SetRated(false); - GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bracketEntry, isRated != 0, false, arenaRating, matchmakerRating, ateamId, previousOpponents); + ginfo = bgQueue.AddGroup(_player, grp, bracketEntry, packet.IsRated, false, arenaRating, matchmakerRating, ateamId, previousOpponents); avgTime = bgQueue.GetAverageQueueWaitTime(ginfo); } @@ -754,23 +655,32 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) if (!member) continue; - WorldPacket data; - if (err <= 0) { - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); - member->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, err, &errorGuid); + member->SendDirectMessage(battlefieldStatus.Write()); continue; } + if (!_player->CanJoinToBattleground(bg)) + { + WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusFailed(&battlefieldStatus, ERR_BATTLEGROUND_JOIN_FAILED, &errorGuid); + member->SendDirectMessage(battlefieldStatus.Write()); + return; + } + // add to queue uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype, 0); - member->SendDirectMessage(&data); - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); - member->SendDirectMessage(&data); + WorldPackets::Battleground::BattlefieldStatusQueued battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusQueued(&battlefieldStatus, bg, queueSlot, ginfo->JoinTime, bgQueueTypeId, avgTime); + member->SendDirectMessage(battlefieldStatus.Write()); + + WorldPackets::Battleground::GroupJoinedBattleground groupJoinedBattleground; + BattlegroundMgr::BuildGroupJoinedBattlegroundPacket(&groupJoinedBattleground, BattlegroundTypeId(err)); + member->SendDirectMessage(groupJoinedBattleground.Write()); TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena as group bg queue {{ BattlemasterListId: {}, BracketId: {}, TeamSize: {} }}, {}, NAME {}", bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.BracketId), uint32(bgQueueTypeId.TeamSize), member->GetGUID().ToString(), member->GetName()); @@ -778,30 +688,28 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) } else { - GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bracketEntry, isRated != 0, false, arenaRating, matchmakerRating, ateamId, previousOpponents); + GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bracketEntry, packet.IsRated, false, arenaRating, matchmakerRating, ateamId, previousOpponents); uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo); uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); - WorldPacket data; - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype, 0); - SendPacket(&data); + WorldPackets::Battleground::BattlefieldStatusQueued battlefieldStatus; + BattlegroundMgr::BuildBattlegroundStatusQueued(&battlefieldStatus, bg, queueSlot, ginfo->JoinTime, bgQueueTypeId, avgTime); + SendPacket(battlefieldStatus.Write()); + TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena, skirmish, bg queue type {{ BattlemasterListId: {}, BracketId: {}, TeamSize: {} }}: {}, NAME {}", bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.BracketId), uint32(bgQueueTypeId.TeamSize), _player->GetGUID().ToString(), _player->GetName()); } + sBattlegroundMgr->ScheduleQueueUpdate(matchmakerRating, bgQueueTypeId); } -void WorldSession::HandleReportPvPAFK(WorldPacket& recvData) +void WorldSession::HandleReportPvPAFK(WorldPackets::Battleground::ReportPvPPlayerAFK& reportPvPPlayerAFK) { - ObjectGuid playerGuid; - recvData >> playerGuid; - Player* reportedPlayer = ObjectAccessor::FindPlayer(playerGuid); - + Player* reportedPlayer = ObjectAccessor::FindPlayer(reportPvPPlayerAFK.Offender); if (!reportedPlayer) { - TC_LOG_INFO("bg.reportpvpafk", "WorldSession::HandleReportPvPAFK: {} [IP: {}] reported {}", _player->GetName(), _player->GetSession()->GetRemoteAddress(), playerGuid.ToString()); + TC_LOG_INFO("bg.reportpvpafk", "WorldSession::HandleReportPvPAFK: {} [IP: {}] reported {}", _player->GetName(), _player->GetSession()->GetRemoteAddress(), reportPvPPlayerAFK.Offender.ToString()); return; } @@ -809,3 +717,56 @@ void WorldSession::HandleReportPvPAFK(WorldPacket& recvData) reportedPlayer->ReportedAfkBy(_player); } + +void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPackets::Battleground::AreaSpiritHealerQuery& areaSpiritHealerQuery) +{ + Player* player = GetPlayer(); + Creature* spiritHealer = ObjectAccessor::GetCreature(*player, areaSpiritHealerQuery.HealerGuid); + if (!spiritHealer) + return; + + if (!spiritHealer->IsSpiritService()) + return; + + if (Battleground* bg = _player->GetBattleground()) + sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, areaSpiritHealerQuery.HealerGuid); + + if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetZoneId())) + bf->SendAreaSpiritHealerQueryOpcode(_player, areaSpiritHealerQuery.HealerGuid); +} + +void WorldSession::HandleAreaSpiritHealerQueueOpcode(WorldPackets::Battleground::AreaSpiritHealerQueue& areaSpiritHealerQueue) +{ + Creature* spiritHealer = ObjectAccessor::GetCreature(*GetPlayer(), areaSpiritHealerQueue.HealerGuid); + if (!spiritHealer) + return; + + if (!spiritHealer->IsSpiritService()) + return; + + if (Battleground* bg = _player->GetBattleground()) + bg->AddPlayerToResurrectQueue(areaSpiritHealerQueue.HealerGuid, _player->GetGUID()); + + if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetZoneId())) + bf->AddPlayerToResurrectQueue(areaSpiritHealerQueue.HealerGuid, _player->GetGUID()); +} + +void WorldSession::HandleHearthAndResurrect(WorldPackets::Battleground::HearthAndResurrect& /*hearthAndResurrect*/) +{ + if (_player->IsInFlight()) + return; + + if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetZoneId())) + { + bf->PlayerAskToLeave(_player); + return; + } + + AreaTableEntry const* atEntry = sAreaTableStore.LookupEntry(_player->GetAreaId()); + if (!atEntry || !(atEntry->Flags & AREA_FLAG_WINTERGRASP_2)) + return; + + _player->BuildPlayerRepop(); + _player->ResurrectPlayer(1.0f); + _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); +} diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index eda9900a26ef8..29d61b6434020 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -17,9 +17,6 @@ #include "WorldSession.h" #include "AccountMgr.h" -#include "Battlefield.h" -#include "BattlefieldMgr.h" -#include "Battleground.h" #include "BattlegroundMgr.h" #include "CharacterPackets.h" #include "Chat.h" @@ -1327,72 +1324,6 @@ void WorldSession::SendSetPhaseShift(uint32 PhaseShift) data << uint32(PhaseShift); SendPacket(&data); } -// Battlefield and Battleground -void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPacket& recvData) -{ - TC_LOG_DEBUG("network", "WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY"); - - Battleground* bg = _player->GetBattleground(); - - ObjectGuid guid; - recvData >> guid; - - Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->IsSpiritService()) // it's not spirit service - return; - - if (bg) - sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, guid); - - if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetZoneId())) - bf->SendAreaSpiritHealerQueryOpcode(_player, guid); -} - -void WorldSession::HandleAreaSpiritHealerQueueOpcode(WorldPacket& recvData) -{ - TC_LOG_DEBUG("network", "WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE"); - - Battleground* bg = _player->GetBattleground(); - - ObjectGuid guid; - recvData >> guid; - - Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->IsSpiritService()) // it's not spirit service - return; - - if (bg) - bg->AddPlayerToResurrectQueue(guid, _player->GetGUID()); - - if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetZoneId())) - bf->AddPlayerToResurrectQueue(guid, _player->GetGUID()); -} - -void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recvData*/) -{ - if (_player->IsInFlight()) - return; - - if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetZoneId())) - { - bf->PlayerAskToLeave(_player); - return; - } - - AreaTableEntry const* atEntry = sAreaTableStore.LookupEntry(_player->GetAreaId()); - if (!atEntry || !(atEntry->Flags & AREA_FLAG_WINTERGRASP_2)) - return; - - _player->BuildPlayerRepop(); - _player->ResurrectPlayer(1.0f); - _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); -} void WorldSession::HandleInstanceLockResponse(WorldPacket& recvPacket) { diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h index 041ea5b759939..de8cc0b7524e1 100644 --- a/src/server/game/Server/Packets/AllPackets.h +++ b/src/server/game/Server/Packets/AllPackets.h @@ -19,6 +19,7 @@ #define AllPackets_h__ #include "BankPackets.h" +#include "BattlegroundPackets.h" #include "CalendarPackets.h" #include "CharacterPackets.h" #include "ChatPackets.h" diff --git a/src/server/game/Server/Packets/BattlegroundPackets.cpp b/src/server/game/Server/Packets/BattlegroundPackets.cpp new file mode 100644 index 0000000000000..460820e900a01 --- /dev/null +++ b/src/server/game/Server/Packets/BattlegroundPackets.cpp @@ -0,0 +1,272 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "BattlegroundPackets.h" +#include "Battleground.h" + +void WorldPackets::Battleground::AreaSpiritHealerQuery::Read() +{ + _worldPacket >> HealerGuid; +} + +void WorldPackets::Battleground::AreaSpiritHealerQueue::Read() +{ + _worldPacket >> HealerGuid; +} + +WorldPacket const* WorldPackets::Battleground::AreaSpiritHealerTime::Write() +{ + _worldPacket << HealerGuid; + _worldPacket << int32(TimeLeft); + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Battleground::PVPLogData_RatingData const& ratingData) +{ + for (std::size_t i = 0; i < 2; ++i) + { + data << int32(ratingData.Prematch[i]); + data << int32(ratingData.Postmatch[i]); + data << int32(ratingData.PrematchMMR[i]); + } + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Battleground::PVPLogData_Arena const& arena) +{ + data << arena.Ratings; + for (std::string_view const& teamName : arena.TeamName) + data << teamName; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Battleground::PVPLogData_Honor const& honorData) +{ + data << uint32(honorData.HonorKills); + data << uint32(honorData.Deaths); + data << uint32(honorData.ContributionPoints); + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Battleground::PVPLogData_Player const& playerData) +{ + data << playerData.PlayerGUID; + data << uint32(playerData.Kills); + std::visit([&](auto const& v) { return data << v; }, playerData.HonorOrFaction); + data << uint32(playerData.DamageDone); + data << uint32(playerData.HealingDone); + data << uint32(playerData.Stats.size()); + for (uint32 pvpStat : playerData.Stats) + data << uint32(pvpStat); + + return data; +} + +WorldPacket const* WorldPackets::Battleground::PVPMatchStatistics::Write() +{ + _worldPacket.reserve(sizeof(PVPLogData_Arena) + 1 + 1 + 4 + Players.size() * sizeof(PVPLogData_Player)); + + _worldPacket << uint8(Arena.has_value()); + if (Arena) + _worldPacket << *Arena; + + _worldPacket << uint8(Winner.has_value()); + if (Winner) + _worldPacket << uint8(*Winner); + + _worldPacket << uint32(Players.size()); + for (PVPLogData_Player const& player : Players) + _worldPacket << player; + + return &_worldPacket; +} + +void WorldPackets::Battleground::BattlemasterJoin::Read() +{ + _worldPacket >> BattlemasterGuid; + _worldPacket >> BattlemasterListID; + _worldPacket >> InstanceID; + _worldPacket >> JoinAsGroup; +} + +void WorldPackets::Battleground::BattlemasterJoinArena::Read() +{ + _worldPacket >> BattlemasterGuid; + _worldPacket >> TeamSizeIndex; + _worldPacket >> JoinAsGroup; + _worldPacket >> IsRated; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Battleground::BattlefieldStatusHeader const& header) +{ + data << uint32(header.QueueSlot); + data << uint64(header.QueueID); + data << uint8(header.RangeMin); + data << uint8(header.RangeMax); + data << uint32(header.InstanceID); + data << uint8(header.RegisteredMatch); + return data; +} + +WorldPacket const* WorldPackets::Battleground::BattlefieldStatusNone::Write() +{ + _worldPacket << uint32(QueueSlot); + _worldPacket << uint64(0); + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Battleground::BattlefieldStatusNeedConfirmation::Write() +{ + _worldPacket << Hdr; + _worldPacket << uint32(STATUS_WAIT_JOIN); + _worldPacket << uint32(Mapid); + _worldPacket << uint64(RandomQueueID); + _worldPacket << uint32(Timeout); + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Battleground::BattlefieldStatusActive::Write() +{ + _worldPacket << Hdr; + _worldPacket << uint32(STATUS_IN_PROGRESS); + _worldPacket << uint32(Mapid); + _worldPacket << uint64(RandomQueueID); + _worldPacket << uint32(ShutdownTimer); + _worldPacket << uint32(StartTimer); + _worldPacket << uint8(ArenaFaction); + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Battleground::BattlefieldStatusQueued::Write() +{ + _worldPacket << Hdr; + _worldPacket << uint32(STATUS_WAIT_QUEUE); + _worldPacket << uint32(AverageWaitTime); + _worldPacket << uint32(WaitTime); + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Battleground::GroupJoinedBattleground::Write() +{ + _worldPacket << uint32(Reason); + if (Reason == ERR_BATTLEGROUND_JOIN_TIMED_OUT || Reason == ERR_BATTLEGROUND_JOIN_FAILED) + _worldPacket << ClientID; + + return &_worldPacket; +} + +void WorldPackets::Battleground::BattlefieldLeave::Read() +{ + _worldPacket >> QueueID; +} + +void WorldPackets::Battleground::BattlefieldPort::Read() +{ + _worldPacket >> QueueID; + _worldPacket >> AcceptedInvite; +} + +void WorldPackets::Battleground::BattlefieldListRequest::Read() +{ + _worldPacket >> ListID; + _worldPacket >> PvpAnywhere; + _worldPacket >> NoXpGain; +} + +WorldPacket const* WorldPackets::Battleground::BattlefieldList::Write() +{ + _worldPacket << BattlemasterGuid; + _worldPacket << uint8(PvpAnywhere); + _worldPacket << int32(BattlemasterListID); + _worldPacket << uint8(MinLevel); + _worldPacket << uint8(MaxLevel); + + _worldPacket << uint8(HasHolidayWinToday); + _worldPacket << uint32(HolidayWinHonorCurrencyBonus); + _worldPacket << uint32(HolidayFirstWinArenaCurrencyBonus); + _worldPacket << uint32(HolidayLossHonorCurrencyBonus); + + _worldPacket << uint8(BattlemasterListID == BATTLEGROUND_RB); + if (BattlemasterListID == BATTLEGROUND_RB) + { + _worldPacket << uint8(HasRandomWinToday); + _worldPacket << uint32(RandomWinHonorCurrencyBonus); + _worldPacket << uint32(RandomFirstWinArenaCurrencyBonus); + _worldPacket << uint32(RandomLossHonorCurrencyBonus); + } + + _worldPacket << uint32(Battlefields ? Battlefields->size() : 0); + if (Battlefields) + for (uint32 battlefield : *Battlefields) + _worldPacket << uint32(battlefield); + + return &_worldPacket; +} + +void WorldPackets::Battleground::ReportPvPPlayerAFK::Read() +{ + _worldPacket >> Offender; +} + +WorldPacket const* WorldPackets::Battleground::ReportPvPPlayerAFKResult::Write() +{ + _worldPacket << uint8(Result); + _worldPacket << uint8(NumBlackMarksOnOffender); + _worldPacket << uint8(NumPlayersIHaveReported); + _worldPacket << Offender; + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Battleground::BattlegroundPlayerPosition const& playerPosition) +{ + data << playerPosition.Guid; + data << playerPosition.Pos; + return data; +} + +WorldPacket const* WorldPackets::Battleground::BattlegroundPlayerPositions::Write() +{ + _worldPacket << uint32(Players.size()); + for (BattlegroundPlayerPosition const& pos : Players) + _worldPacket << pos; + + _worldPacket << uint32(FlagCarriers.size()); + for (BattlegroundPlayerPosition const& pos : FlagCarriers) + _worldPacket << pos; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Battleground::BattlegroundPlayerJoined::Write() +{ + _worldPacket << Guid; + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Battleground::BattlegroundPlayerLeft::Write() +{ + _worldPacket << Guid; + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Battleground::DestroyArenaUnit::Write() +{ + _worldPacket << Guid; + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/BattlegroundPackets.h b/src/server/game/Server/Packets/BattlegroundPackets.h new file mode 100644 index 0000000000000..ce143b83ad0b4 --- /dev/null +++ b/src/server/game/Server/Packets/BattlegroundPackets.h @@ -0,0 +1,372 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef BattlegroundPackets_h__ +#define BattlegroundPackets_h__ + +#include "Packet.h" +#include "ObjectGuid.h" +#include "Optional.h" +#include "Position.h" +#include +#include + +namespace WorldPackets +{ + namespace Battleground + { + class AreaSpiritHealerQuery final : public ClientPacket + { + public: + AreaSpiritHealerQuery(WorldPacket&& packet) : ClientPacket(CMSG_AREA_SPIRIT_HEALER_QUERY, std::move(packet)) { } + + void Read() override; + + ObjectGuid HealerGuid; + }; + + class AreaSpiritHealerQueue final : public ClientPacket + { + public: + AreaSpiritHealerQueue(WorldPacket&& packet) : ClientPacket(CMSG_AREA_SPIRIT_HEALER_QUEUE, std::move(packet)) { } + + void Read() override; + + ObjectGuid HealerGuid; + }; + + class AreaSpiritHealerTime final : public ServerPacket + { + public: + AreaSpiritHealerTime() : ServerPacket(SMSG_AREA_SPIRIT_HEALER_TIME, 8 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid HealerGuid; + int32 TimeLeft = 0; + }; + + class HearthAndResurrect final : public ClientPacket + { + public: + HearthAndResurrect(WorldPacket&& packet) : ClientPacket(CMSG_HEARTH_AND_RESURRECT, std::move(packet)) { } + + void Read() override { } + }; + + class PVPLogDataRequest final : public ClientPacket + { + public: + PVPLogDataRequest(WorldPacket&& packet) : ClientPacket(MSG_PVP_LOG_DATA, std::move(packet)) { } + + void Read() override { } + }; + + struct PVPLogData_RatingData + { + std::array Prematch = { }; + std::array Postmatch = { }; + std::array PrematchMMR = { }; + }; + + struct PVPLogData_Arena + { + PVPLogData_RatingData Ratings; + std::array TeamName; + }; + + struct PVPLogData_Honor + { + uint32 HonorKills = 0; + uint32 Deaths = 0; + uint32 ContributionPoints = 0; + }; + + struct PVPLogData_Player + { + ObjectGuid PlayerGUID; + uint32 Kills = 0; + std::variant HonorOrFaction; + uint32 DamageDone = 0; + uint32 HealingDone = 0; + std::vector Stats; + }; + + class PVPMatchStatistics final : public ServerPacket + { + public: + PVPMatchStatistics() : ServerPacket(MSG_PVP_LOG_DATA, 0) { } + + WorldPacket const* Write() override; + + Optional Winner; + std::vector Players; + Optional Arena; + }; + + struct BattlefieldStatusHeader + { + uint32 QueueSlot = 0; + uint64 QueueID = 0; + uint8 RangeMin = 0; + uint8 RangeMax = 0; + uint32 InstanceID = 0; + bool RegisteredMatch = false; + }; + + class BattlefieldStatusNone final : public ServerPacket + { + public: + BattlefieldStatusNone() : ServerPacket(SMSG_BATTLEFIELD_STATUS, 4 + 8) { } + + WorldPacket const* Write() override; + + uint32 QueueSlot = 0; + }; + + class BattlefieldStatusNeedConfirmation final : public ServerPacket + { + public: + BattlefieldStatusNeedConfirmation() : ServerPacket(SMSG_BATTLEFIELD_STATUS, 4 + 4 + sizeof(BattlefieldStatusHeader) + 8) { } + + WorldPacket const* Write() override; + + uint32 Timeout = 0; + uint32 Mapid = 0; + BattlefieldStatusHeader Hdr; + uint64 RandomQueueID = 0; + }; + + class BattlefieldStatusActive final : public ServerPacket + { + public: + BattlefieldStatusActive() : ServerPacket(SMSG_BATTLEFIELD_STATUS, sizeof(BattlefieldStatusHeader) + 4 + 1 + 4 + 4 + 8) { } + + WorldPacket const* Write() override; + + BattlefieldStatusHeader Hdr; + uint32 ShutdownTimer = 0; + uint8 ArenaFaction = 0; + uint32 StartTimer = 0; + uint32 Mapid = 0; + uint64 RandomQueueID = 0; + }; + + class BattlefieldStatusQueued final : public ServerPacket + { + public: + BattlefieldStatusQueued() : ServerPacket(SMSG_BATTLEFIELD_STATUS, 4 + sizeof(BattlefieldStatusHeader) + 4) { } + + WorldPacket const* Write() override; + + uint32 AverageWaitTime = 0; + BattlefieldStatusHeader Hdr; + uint32 WaitTime = 0; + }; + + class GroupJoinedBattleground final : public ServerPacket + { + public: + GroupJoinedBattleground() : ServerPacket(SMSG_GROUP_JOINED_BATTLEGROUND, 8 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid ClientID; + int32 Reason = 0; + }; + + using BattlefieldStatusFailed = GroupJoinedBattleground; + + class BattlemasterJoin final : public ClientPacket + { + public: + BattlemasterJoin(WorldPacket&& packet) : ClientPacket(CMSG_BATTLEMASTER_JOIN, std::move(packet)) { } + + void Read() override; + + ObjectGuid BattlemasterGuid; + uint32 BattlemasterListID = 0; + uint32 InstanceID = 0; + bool JoinAsGroup = false; + }; + + class BattlemasterJoinArena final : public ClientPacket + { + public: + BattlemasterJoinArena(WorldPacket&& packet) : ClientPacket(CMSG_BATTLEMASTER_JOIN_ARENA, std::move(packet)) { } + + void Read() override; + + ObjectGuid BattlemasterGuid; + uint8 TeamSizeIndex = 0; + bool JoinAsGroup = false; + bool IsRated = false; + }; + + class BattlefieldLeave final : public ClientPacket + { + public: + BattlefieldLeave(WorldPacket&& packet) : ClientPacket(CMSG_LEAVE_BATTLEFIELD, std::move(packet)) { } + + void Read() override; + + uint64 QueueID = 0; + }; + + class BattlefieldPort final : public ClientPacket + { + public: + BattlefieldPort(WorldPacket&& packet) : ClientPacket(CMSG_BATTLEFIELD_PORT, std::move(packet)) { } + + void Read() override; + + uint64 QueueID = 0; + bool AcceptedInvite = false; + }; + + class BattlefieldListRequest final : public ClientPacket + { + public: + BattlefieldListRequest(WorldPacket&& packet) : ClientPacket(CMSG_BATTLEFIELD_LIST, std::move(packet)) { } + + void Read() override; + + int32 ListID = 0; + bool PvpAnywhere = false; + bool NoXpGain = false; + }; + + class BattlefieldList final : public ServerPacket + { + public: + BattlefieldList() : ServerPacket(SMSG_BATTLEFIELD_LIST, 8 + 1 + 4 + 1 + 1 + 1 + 4 + 4 + 4 + 1 + 1 + 4 + 4 + 4 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid BattlemasterGuid; + int32 BattlemasterListID = 0; + uint8 MinLevel = 0; + uint8 MaxLevel = 0; + std::set const* Battlefields = nullptr; + bool PvpAnywhere = false; + bool HasHolidayWinToday = false; + uint32 HolidayWinHonorCurrencyBonus = 0; + uint32 HolidayFirstWinArenaCurrencyBonus = 0; + uint32 HolidayLossHonorCurrencyBonus = 0; + bool HasRandomWinToday = false; + uint32 RandomWinHonorCurrencyBonus = 0; + uint32 RandomFirstWinArenaCurrencyBonus = 0; + uint32 RandomLossHonorCurrencyBonus = 0; + }; + + class RequestBattlefieldStatus final : public ClientPacket + { + public: + RequestBattlefieldStatus(WorldPacket&& packet) : ClientPacket(CMSG_BATTLEFIELD_STATUS, std::move(packet)) { } + + void Read() override { } + }; + + class ReportPvPPlayerAFK final : public ClientPacket + { + public: + ReportPvPPlayerAFK(WorldPacket&& packet) : ClientPacket(CMSG_REPORT_PVP_AFK, std::move(packet)) { } + + void Read() override; + + ObjectGuid Offender; + }; + + class ReportPvPPlayerAFKResult final : public ServerPacket + { + public: + ReportPvPPlayerAFKResult() : ServerPacket(SMSG_REPORT_PVP_AFK_RESULT, 8 + 1 + 1 + 1) { } + + WorldPacket const* Write() override; + + enum ResultCode : uint8 + { + PVP_REPORT_AFK_SUCCESS = 0, + PVP_REPORT_AFK_GENERIC_FAILURE = 1, // there are more error codes but they are impossible to receive without modifying the client + PVP_REPORT_AFK_SYSTEM_ENABLED = 5, + PVP_REPORT_AFK_SYSTEM_DISABLED = 6 + }; + + ObjectGuid Offender; + uint8 NumPlayersIHaveReported = 0; + uint8 NumBlackMarksOnOffender = 0; + uint8 Result = PVP_REPORT_AFK_GENERIC_FAILURE; + }; + + class BattlegroundPlayerPositionsRequest final : public ClientPacket + { + public: + BattlegroundPlayerPositionsRequest(WorldPacket&& packet) : ClientPacket(MSG_BATTLEGROUND_PLAYER_POSITIONS, std::move(packet)) { } + + void Read() override { } + }; + + struct BattlegroundPlayerPosition + { + ObjectGuid Guid; + TaggedPosition Pos; + }; + + class BattlegroundPlayerPositions final : public ServerPacket + { + public: + BattlegroundPlayerPositions() : ServerPacket(MSG_BATTLEGROUND_PLAYER_POSITIONS, 4 + 4) { } + + WorldPacket const* Write() override; + + std::vector Players; + std::vector FlagCarriers; + }; + + class BattlegroundPlayerJoined final : public ServerPacket + { + public: + BattlegroundPlayerJoined() : ServerPacket(SMSG_BATTLEGROUND_PLAYER_JOINED, 8) { } + + WorldPacket const* Write() override; + + ObjectGuid Guid; + }; + + class BattlegroundPlayerLeft final : public ServerPacket + { + public: + BattlegroundPlayerLeft() : ServerPacket(SMSG_BATTLEGROUND_PLAYER_LEFT, 8) { } + + WorldPacket const* Write() override; + + ObjectGuid Guid; + }; + + class DestroyArenaUnit final : public ServerPacket + { + public: + DestroyArenaUnit() : ServerPacket(SMSG_ARENA_UNIT_DESTROYED, 8) { } + + WorldPacket const* Write() override; + + ObjectGuid Guid; + }; + } +} + +#endif // BattlegroundPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 34710741ecad2..4b10b53f56fa2 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -851,7 +851,7 @@ void OpcodeTable::Initialize() /*0x2D0*/ DEFINE_HANDLER(CMSG_MOVE_WATER_WALK_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveWaterWalkAck ); /*0x2D1*/ DEFINE_HANDLER(CMSG_MOVE_NOT_ACTIVE_MOVER, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveNotActiveMover ); /*0x2D2*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SOUND, STATUS_NEVER); - /*0x2D3*/ DEFINE_HANDLER(CMSG_BATTLEFIELD_STATUS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlefieldStatusOpcode ); + /*0x2D3*/ DEFINE_HANDLER(CMSG_BATTLEFIELD_STATUS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestBattlefieldStatusOpcode); /*0x2D4*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS, STATUS_NEVER); /*0x2D5*/ DEFINE_HANDLER(CMSG_BATTLEFIELD_PORT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattleFieldPortOpcode ); /*0x2D6*/ DEFINE_HANDLER(MSG_INSPECT_HONOR_STATS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleInspectHonorStatsOpcode ); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 8b34a4ee0bf0f..a8c5a892f8795 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -88,6 +88,22 @@ namespace WorldPackets class BuyBankSlot; } + namespace Battleground + { + class AreaSpiritHealerQuery; + class AreaSpiritHealerQueue; + class HearthAndResurrect; + class PVPLogDataRequest; + class BattlemasterJoin; + class BattlemasterJoinArena; + class BattlefieldLeave; + class BattlefieldPort; + class BattlefieldListRequest; + class RequestBattlefieldStatus; + class ReportPvPPlayerAFK; + class BattlegroundPlayerPositionsRequest; + } + namespace Calendar { class CalendarAddEvent; @@ -541,8 +557,6 @@ class TC_GAME_API WorldSession void SendAttackStop(Unit const* enemy); - void SendBattleGroundList(ObjectGuid guid, BattlegroundTypeId bgTypeId = BATTLEGROUND_RB); - void SendTradeStatus(TradeStatusInfo const& status); void SendUpdateTrade(bool trader_data = true); void SendCancelTrade(TradeStatus status); @@ -789,8 +803,6 @@ class TC_GAME_API WorldSession void HandleRequestRaidInfoOpcode(WorldPacket& recvData); - void HandleBattlefieldStatusOpcode(WorldPacket& recvData); - void HandleGroupInviteOpcode(WorldPackets::Party::PartyInviteClient& packet); void HandleGroupAcceptOpcode(WorldPacket& recvPacket); void HandleGroupDeclineOpcode(WorldPacket& recvPacket); @@ -1023,15 +1035,19 @@ class TC_GAME_API WorldSession void HandleDismissCritter(WorldPackets::Pet::DismissCritter& dismissCritter); //Battleground - void HandleBattlemasterHelloOpcode(WorldPacket& recvData); - void HandleBattlemasterJoinOpcode(WorldPacket& recvData); - void HandleBattlegroundPlayerPositionsOpcode(WorldPacket& recvData); - void HandlePVPLogDataOpcode(WorldPacket& recvData); - void HandleBattleFieldPortOpcode(WorldPacket& recvData); - void HandleBattlefieldListOpcode(WorldPacket& recvData); - void HandleBattlefieldLeaveOpcode(WorldPacket& recvData); - void HandleBattlemasterJoinArena(WorldPacket& recvData); - void HandleReportPvPAFK(WorldPacket& recvData); + void HandleBattlemasterHelloOpcode(WorldPackets::NPC::Hello& hello); + void HandleBattlemasterJoinOpcode(WorldPackets::Battleground::BattlemasterJoin& battlemasterJoin); + void HandleBattlegroundPlayerPositionsOpcode(WorldPackets::Battleground::BattlegroundPlayerPositionsRequest& battlegroundPlayerPositionsRequest); + void HandlePVPLogDataOpcode(WorldPackets::Battleground::PVPLogDataRequest& pvpLogDataRequest); + void HandleBattleFieldPortOpcode(WorldPackets::Battleground::BattlefieldPort& battlefieldPort); + void HandleBattlefieldListOpcode(WorldPackets::Battleground::BattlefieldListRequest& battlefieldList); + void HandleBattlefieldLeaveOpcode(WorldPackets::Battleground::BattlefieldLeave& battlefieldLeave); + void HandleBattlemasterJoinArena(WorldPackets::Battleground::BattlemasterJoinArena& packet); + void HandleReportPvPAFK(WorldPackets::Battleground::ReportPvPPlayerAFK& reportPvPPlayerAFK); + void HandleAreaSpiritHealerQueryOpcode(WorldPackets::Battleground::AreaSpiritHealerQuery& areaSpiritHealerQuery); + void HandleAreaSpiritHealerQueueOpcode(WorldPackets::Battleground::AreaSpiritHealerQueue& areaSpiritHealerQueue); + void HandleHearthAndResurrect(WorldPackets::Battleground::HearthAndResurrect& hearthAndResurrect); + void HandleRequestBattlefieldStatusOpcode(WorldPackets::Battleground::RequestBattlefieldStatus& requestBattlefieldStatus); // Battlefield void SendBfInvitePlayerToWar(uint32 battleId, uint32 zoneId, uint32 time); @@ -1055,7 +1071,6 @@ class TC_GAME_API WorldSession void HandleTimeSyncResponse(WorldPacket& recvData); void HandleWhoIsOpcode(WorldPacket& recvData); void HandleResetInstancesOpcode(WorldPacket& recvData); - void HandleHearthAndResurrect(WorldPacket& recvData); void HandleInstanceLockResponse(WorldPacket& recvPacket); // Looking for Dungeon/Raid @@ -1098,8 +1113,6 @@ class TC_GAME_API WorldSession void HandleArenaTeamDisbandOpcode(WorldPacket& recvData); void HandleArenaTeamLeaderOpcode(WorldPacket& recvData); - void HandleAreaSpiritHealerQueryOpcode(WorldPacket& recvData); - void HandleAreaSpiritHealerQueueOpcode(WorldPacket& recvData); void HandleSelfResOpcode(WorldPacket& recvData); void HandleComplainOpcode(WorldPacket& recvData); void HandleRequestPetInfo(WorldPackets::Pet::RequestPetInfo& packet);