/*
* 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 "QueryPackets.h"
#include "BattlenetAccountMgr.h"
#include "CharacterCache.h"
#include "ClubUtils.h"
#include "ObjectMgr.h"
#include "PacketOperators.h"
#include "Player.h"
#include "World.h"
ByteBuffer& operator<<(ByteBuffer& data, QuestPOIData const& questPOIData)
{
data << int32(questPOIData.QuestID);
data << WorldPackets::Size(questPOIData.Blobs);
for (QuestPOIBlobData const& questPOIBlobData : questPOIData.Blobs)
{
data << int32(questPOIBlobData.BlobIndex);
data << int32(questPOIBlobData.ObjectiveIndex);
data << int32(questPOIBlobData.QuestObjectiveID);
data << int32(questPOIBlobData.QuestObjectID);
data << int32(questPOIBlobData.MapID);
data << int32(questPOIBlobData.UiMapID);
data << int32(questPOIBlobData.Priority);
data << int32(questPOIBlobData.Flags);
data << int32(questPOIBlobData.WorldEffectID);
data << int32(questPOIBlobData.PlayerConditionID);
data << int32(questPOIBlobData.NavigationPlayerConditionID);
data << int32(questPOIBlobData.SpawnTrackingID);
data << WorldPackets::Size(questPOIBlobData.Points);
for (QuestPOIBlobPoint const& questPOIBlobPoint : questPOIBlobData.Points)
{
data << int16(questPOIBlobPoint.X);
data << int16(questPOIBlobPoint.Y);
data << int16(questPOIBlobPoint.Z);
}
data << WorldPackets::Bits<1>(questPOIBlobData.AlwaysAllowMergingBlobs);
data.FlushBits();
}
return data;
}
namespace WorldPackets::Query
{
void QueryCreature::Read()
{
_worldPacket >> CreatureID;
}
WorldPacket const* QueryCreatureResponse::Write()
{
_worldPacket << uint32(CreatureID);
_worldPacket << Bits<1>(Allow);
_worldPacket.FlushBits();
if (Allow)
{
_worldPacket << SizedCString::BitsSize<11>(Stats.Title);
_worldPacket << SizedCString::BitsSize<11>(Stats.TitleAlt);
_worldPacket << SizedCString::BitsSize<6>(Stats.CursorName);
_worldPacket << Bits<1>(Stats.Leader);
for (std::size_t i = 0; i < Stats.Name.size(); ++i)
{
_worldPacket << SizedCString::BitsSize<11>(Stats.Name[i]);
_worldPacket << SizedCString::BitsSize<11>(Stats.NameAlt[i]);
}
for (std::size_t i = 0; i < Stats.Name.size(); ++i)
{
_worldPacket << SizedCString::Data(Stats.Name[i]);
_worldPacket << SizedCString::Data(Stats.NameAlt[i]);
}
_worldPacket.append(Stats.Flags.data(), Stats.Flags.size());
_worldPacket << uint8(Stats.CreatureType);
_worldPacket << int32(Stats.CreatureFamily);
_worldPacket << int8(Stats.Classification);
_worldPacket.append(Stats.ProxyCreatureID.data(), Stats.ProxyCreatureID.size());
_worldPacket << Size(Stats.Display.CreatureDisplay);
_worldPacket << float(Stats.Display.TotalProbability);
for (CreatureXDisplay const& display : Stats.Display.CreatureDisplay)
{
_worldPacket << uint32(display.CreatureDisplayID);
_worldPacket << float(display.Scale);
_worldPacket << float(display.Probability);
}
_worldPacket << float(Stats.HpMulti);
_worldPacket << float(Stats.EnergyMulti);
_worldPacket << Size(Stats.QuestItems);
_worldPacket << Size(Stats.QuestCurrencies);
_worldPacket << int32(Stats.CreatureMovementInfoID);
_worldPacket << int32(Stats.HealthScalingExpansion);
_worldPacket << int32(Stats.RequiredExpansion);
_worldPacket << int32(Stats.VignetteID);
_worldPacket << int32(Stats.Class);
_worldPacket << int32(Stats.CreatureDifficultyID);
_worldPacket << int32(Stats.WidgetSetID);
_worldPacket << int32(Stats.WidgetSetUnitConditionID);
_worldPacket << SizedCString::Data(Stats.Title);
_worldPacket << SizedCString::Data(Stats.TitleAlt);
_worldPacket << SizedCString::Data(Stats.CursorName);
if (!Stats.QuestItems.empty())
_worldPacket.append(Stats.QuestItems.data(), Stats.QuestItems.size());
if (!Stats.QuestCurrencies.empty())
_worldPacket.append(Stats.QuestCurrencies.data(), Stats.QuestCurrencies.size());
}
return &_worldPacket;
}
void QueryPlayerNames::Read()
{
_worldPacket >> Size(Players);
for (ObjectGuid& player : Players)
_worldPacket >> player;
}
bool PlayerGuidLookupData::Initialize(ObjectGuid const& guid, Player const* player /*= nullptr*/)
{
CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(guid);
if (!characterInfo)
return false;
if (player)
{
ASSERT(player->GetGUID() == guid);
AccountID = player->m_playerData->WowAccount;
BnetAccountID = player->m_playerData->BnetAccount;
Name = player->GetName();
Race = player->GetRace();
Sex = player->GetNativeGender();
ClassID = player->GetClass();
Level = player->GetLevel();
PvpFaction = player->GetTeamId() == TEAM_ALLIANCE ? 1 : 0;
TimerunningSeasonID = player->m_activePlayerData->TimerunningSeasonID;
if (UF::DeclinedNames const* names = player->GetDeclinedNames())
DeclinedNames = *names;
}
else
{
uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(guid);
uint32 bnetAccountId = ::Battlenet::AccountMgr::GetIdByGameAccount(accountId);
AccountID = ObjectGuid::Create(accountId);
BnetAccountID = ObjectGuid::Create(bnetAccountId);
Name = characterInfo->Name;
Race = characterInfo->Race;
Sex = characterInfo->Sex;
ClassID = characterInfo->Class;
Level = characterInfo->Level;
PvpFaction = Player::TeamIdForRace(characterInfo->Race) == TEAM_ALLIANCE ? 1 : 0;
}
IsDeleted = characterInfo->IsDeleted;
GuidActual = guid;
GuildClubMemberID = ::Battlenet::Services::Clubs::CreateClubMemberId(guid);
VirtualRealmAddress = GetVirtualRealmAddress();
return true;
}
ByteBuffer& operator<<(ByteBuffer& data, PlayerGuidLookupData const& lookupData)
{
data << Bits<1>(lookupData.IsDeleted);
data << SizedString::BitsSize<6>(lookupData.Name);
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
data << SizedString::BitsSize<7>(lookupData.DeclinedNames.name[i]);
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
data << SizedString::Data(lookupData.DeclinedNames.name[i]);
data << lookupData.AccountID;
data << lookupData.BnetAccountID;
data << lookupData.GuidActual;
data << uint64(lookupData.GuildClubMemberID);
data << uint32(lookupData.VirtualRealmAddress);
data << uint8(lookupData.Race);
data << uint8(lookupData.Sex);
data << uint8(lookupData.ClassID);
data << uint8(lookupData.Level);
data << uint8(lookupData.PvpFaction);
data << int32(lookupData.TimerunningSeasonID);
data << SizedString::Data(lookupData.Name);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, GuildGuidLookupData const& lookupData)
{
data << uint32(lookupData.VirtualRealmAddress);
data << lookupData.Guid;
data << SizedString::BitsSize<7>(lookupData.Name);
data.FlushBits();
data << SizedString::Data(lookupData.Name);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, HouseLookupData const& lookupData)
{
data << lookupData.Guid;
data << SizedString::BitsSize<8>(lookupData.Name);
data.FlushBits();
data << SizedString::Data(lookupData.Name);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, NameCacheLookupResult const& result)
{
data << uint8(result.Result);
data << result.Player;
data << OptionalInit(result.Data);
data << OptionalInit(result.GuildData);
data << OptionalInit(result.HouseData);
data.FlushBits();
if (result.Data)
data << *result.Data;
if (result.GuildData)
data << *result.GuildData;
if (result.HouseData)
data << *result.HouseData;
return data;
}
WorldPacket const* QueryPlayerNamesResponse::Write()
{
_worldPacket << Size(Players);
for (NameCacheLookupResult const& lookupResult : Players)
_worldPacket << lookupResult;
return &_worldPacket;
}
void QueryPageText::Read()
{
_worldPacket >> PageTextID;
_worldPacket >> ItemGUID;
}
ByteBuffer& operator<<(ByteBuffer& data, QueryPageTextResponse::PageTextInfo const& page)
{
data << uint32(page.ID);
data << uint32(page.NextPageID);
data << int32(page.PlayerConditionID);
data << uint8(page.Flags);
data << SizedString::BitsSize<12>(page.Text);
data.FlushBits();
data << SizedString::Data(page.Text);
return data;
}
WorldPacket const* QueryPageTextResponse::Write()
{
_worldPacket << uint32(PageTextID);
_worldPacket << Bits<1>(Allow);
_worldPacket.FlushBits();
if (Allow)
{
_worldPacket << Size(Pages);
for (PageTextInfo const& pageText : Pages)
_worldPacket << pageText;
}
return &_worldPacket;
}
void QueryNPCText::Read()
{
_worldPacket >> TextID;
_worldPacket >> Guid;
}
WorldPacket const* QueryNPCTextResponse::Write()
{
_worldPacket << uint32(TextID);
_worldPacket << Bits<1>(Allow);
_worldPacket.FlushBits();
_worldPacket << int32(Allow ? (MAX_NPC_TEXT_OPTIONS * (sizeof(float) + sizeof(uint32))) : 0);
if (Allow)
{
_worldPacket.append(Probabilities.data(), Probabilities.size());
_worldPacket.append(BroadcastTextID.data(), BroadcastTextID.size());
}
return &_worldPacket;
}
void QueryGameObject::Read()
{
_worldPacket >> GameObjectID;
_worldPacket >> Guid;
}
WorldPacket const* QueryGameObjectResponse::Write()
{
_worldPacket << GameObjectID;
_worldPacket << Guid;
_worldPacket << Bits<1>(Allow);
_worldPacket.FlushBits();
ByteBuffer statsData;
if (Allow)
{
statsData << int32(Stats.Type);
statsData << int32(Stats.DisplayID);
for (int8 i = 0; i < 4; ++i)
statsData << Stats.Name[i];
statsData << Stats.IconName;
statsData << Stats.CastBarCaption;
statsData << Stats.UnkString;
for (uint32 i = 0; i < MAX_GAMEOBJECT_DATA; ++i)
statsData << int32(Stats.Data[i]);
statsData << float(Stats.Size);
statsData << Size(Stats.QuestItems);
if (!Stats.QuestItems.empty())
statsData.append(Stats.QuestItems.data(), Stats.QuestItems.size());
statsData << int32(Stats.ContentTuningId);
statsData << int32(Stats.RequiredLevel);
}
_worldPacket << Size(statsData);
if (!statsData.empty())
_worldPacket.append(statsData);
return &_worldPacket;
}
void QueryCorpseLocationFromClient::Read()
{
_worldPacket >> Player;
}
WorldPacket const* CorpseLocation::Write()
{
_worldPacket << Bits<1>(Valid);
_worldPacket.FlushBits();
_worldPacket << Player;
_worldPacket << ActualMapID;
_worldPacket << MapID;
_worldPacket << Transport;
_worldPacket << Position;
return &_worldPacket;
}
void QueryCorpseTransport::Read()
{
_worldPacket >> Player;
_worldPacket >> Transport;
}
WorldPacket const* CorpseTransportQuery::Write()
{
_worldPacket << Player;
_worldPacket << Position;
_worldPacket << Facing;
return &_worldPacket;
}
WorldPacket const* QueryTimeResponse::Write()
{
_worldPacket << CurrentTime;
return &_worldPacket;
}
void QuestPOIQuery::Read()
{
_worldPacket >> MissingQuestCount;
if (MissingQuestCount > std::ssize(MissingQuestPOIs))
OnInvalidArraySize(MissingQuestCount, MissingQuestPOIs.size());
for (std::size_t i = 0; i < MissingQuestPOIs.size(); ++i)
_worldPacket >> MissingQuestPOIs[i];
}
WorldPacket const* QuestPOIQueryResponse::Write()
{
_worldPacket << Size(QuestPOIDataStats);
_worldPacket << Size(QuestPOIDataStats);
bool useCache = sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES);
for (QuestPOIData const* questPOIData : QuestPOIDataStats)
{
if (useCache)
_worldPacket.append(questPOIData->QueryDataBuffer);
else
_worldPacket << *questPOIData;
}
return &_worldPacket;
}
void QueryQuestCompletionNPCs::Read()
{
_worldPacket >> Size(QuestCompletionNPCs);
if (!QuestCompletionNPCs.empty())
_worldPacket.read(QuestCompletionNPCs.data(), QuestCompletionNPCs.size());
}
WorldPacket const* QuestCompletionNPCResponse::Write()
{
_worldPacket << Size(QuestCompletionNPCs);
for (QuestCompletionNPC& quest : QuestCompletionNPCs)
{
_worldPacket << int32(quest.QuestID);
_worldPacket << Size(quest.NPCs);
if (!quest.NPCs.empty())
_worldPacket.append(quest.NPCs.data(), quest.NPCs.size());
}
return &_worldPacket;
}
void QueryPetName::Read()
{
_worldPacket >> UnitGUID;
}
WorldPacket const* QueryPetNameResponse::Write()
{
_worldPacket << UnitGUID;
_worldPacket << Bits<1>(Allow);
if (Allow)
{
_worldPacket << SizedString::BitsSize<8>(Name);
_worldPacket << Bits<1>(HasDeclined);
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
_worldPacket << SizedString::BitsSize<7>(DeclinedNames.name[i]);
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
_worldPacket << SizedString::Data(DeclinedNames.name[i]);
_worldPacket << Timestamp;
_worldPacket << SizedString::Data(Name);
}
else
_worldPacket.FlushBits();
return &_worldPacket;
}
void ItemTextQuery::Read()
{
_worldPacket >> Id;
}
ByteBuffer& operator<<(ByteBuffer& data, ItemTextCache const& itemTextCache)
{
data << SizedString::BitsSize<13>(itemTextCache.Text);
data.FlushBits();
data << SizedString::Data(itemTextCache.Text);
return data;
}
WorldPacket const* QueryItemTextResponse::Write()
{
_worldPacket << Bits<1>(Valid);
_worldPacket.FlushBits();
_worldPacket << Item;
_worldPacket << Id;
return &_worldPacket;
}
void QueryRealmName::Read()
{
_worldPacket >> VirtualRealmAddress;
}
WorldPacket const* RealmQueryResponse::Write()
{
_worldPacket << uint32(VirtualRealmAddress);
_worldPacket << uint8(LookupState);
if (!LookupState)
_worldPacket << NameInfo;
return &_worldPacket;
}
void QueryTreasurePicker::Read()
{
_worldPacket >> QuestID;
_worldPacket >> TreasurePickerID;
}
ByteBuffer& operator<<(ByteBuffer& data, TreasurePickItem const& treasurePickItem)
{
data << treasurePickItem.Item;
data << uint32(treasurePickItem.Quantity);
data << OptionalInit(treasurePickItem.ContextFlags);
data.FlushBits();
if (treasurePickItem.ContextFlags)
data << As(*treasurePickItem.ContextFlags);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, TreasurePickCurrency const& treasurePickCurrency)
{
data << uint32(treasurePickCurrency.CurrencyID);
data << uint32(treasurePickCurrency.Quantity);
data << OptionalInit(treasurePickCurrency.ContextFlags);
data.FlushBits();
if (treasurePickCurrency.ContextFlags)
data << As(*treasurePickCurrency.ContextFlags);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, TreasurePickerBonus const& treasurePickerBonus)
{
data << Size(treasurePickerBonus.ItemPicks);
data << Size(treasurePickerBonus.CurrencyPicks);
data << uint64(treasurePickerBonus.Gold);
data << Bits<1>(treasurePickerBonus.Context);
data.FlushBits();
for (TreasurePickItem const& treasurePickerItem : treasurePickerBonus.ItemPicks)
data << treasurePickerItem;
for (TreasurePickCurrency const& treasurePickCurrency : treasurePickerBonus.CurrencyPicks)
data << treasurePickCurrency;
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, TreasurePickerPick const& treasurePickerPick)
{
data << Size(treasurePickerPick.ItemPicks);
data << Size(treasurePickerPick.CurrencyPicks);
data << uint64(treasurePickerPick.Gold);
data << Size(treasurePickerPick.Bonuses);
data << int32(treasurePickerPick.Flags);
data << Bits<1>(treasurePickerPick.IsChoice);
data.FlushBits();
for (TreasurePickItem const& treasurePickItem : treasurePickerPick.ItemPicks)
data << treasurePickItem;
for (TreasurePickCurrency const& treasurePickCurrency : treasurePickerPick.CurrencyPicks)
data << treasurePickCurrency;
for (TreasurePickerBonus const& treasurePickerBonus : treasurePickerPick.Bonuses)
data << treasurePickerBonus;
return data;
}
WorldPacket const* TreasurePickerResponse::Write()
{
_worldPacket << uint32(QuestID);
_worldPacket << uint32(TreasurePickerID);
_worldPacket << Treasure;
return &_worldPacket;
}
}