diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 75 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 16 | ||||
-rw-r--r-- | src/server/game/Handlers/ItemHandler.cpp | 207 | ||||
-rw-r--r-- | src/server/game/Handlers/VoidStorageHandler.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Server/Packets/ItemPackets.cpp | 56 | ||||
-rw-r--r-- | src/server/game/Server/Packets/ItemPackets.h | 30 | ||||
-rw-r--r-- | src/server/game/Server/Packets/PacketUtilities.h | 10 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 3 |
9 files changed, 246 insertions, 155 deletions
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 70d63a853e7..4d65598c298 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -1298,10 +1298,9 @@ bool Item::CheckSoulboundTradeExpire() return false; } -bool Item::CanBeTransmogrified() const +bool Item::CanBeTransmogrified(WorldPackets::Item::ItemInstance const& transmogrifier, BonusData const* bonus) { - ItemTemplate const* proto = GetTemplate(); - + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(transmogrifier.ItemID); if (!proto) return false; @@ -1318,7 +1317,7 @@ bool Item::CanBeTransmogrified() const if (proto->GetFlags2() & ITEM_FLAG2_CANNOT_BE_TRANSMOG) return false; - if (!HasStats()) + if (!HasStats(transmogrifier, bonus)) return false; return true; @@ -1327,7 +1326,6 @@ bool Item::CanBeTransmogrified() const bool Item::CanTransmogrify() const { ItemTemplate const* proto = GetTemplate(); - if (!proto) return false; @@ -1353,18 +1351,41 @@ bool Item::CanTransmogrify() const return true; } -bool Item::CanTransmogrifyItemWithItem(Item const* transmogrified, Item const* transmogrifier) +bool Item::HasStats() const { - if (!transmogrifier || !transmogrified) - return false; + if (GetItemRandomPropertyId() != 0) + return true; + + ItemTemplate const* proto = GetTemplate(); + Player const* owner = GetOwner(); + for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + if ((owner ? GetItemStatValue(i, owner) : proto->GetItemStatValue(i)) != 0) + return true; + + return false; +} + +bool Item::HasStats(WorldPackets::Item::ItemInstance const& itemInstance, BonusData const* bonus) +{ + if (itemInstance.RandomPropertiesID != 0) + return true; + + for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + if (bonus->ItemStatValue[i] != 0) + return true; + + return false; +} - ItemTemplate const* proto1 = transmogrifier->GetTemplate(); // source +bool Item::CanTransmogrifyItemWithItem(Item const* transmogrified, WorldPackets::Item::ItemInstance const& transmogrifier, BonusData const* bonus) +{ + ItemTemplate const* proto1 = sObjectMgr->GetItemTemplate(transmogrifier.ItemID); // source ItemTemplate const* proto2 = transmogrified->GetTemplate(); // dest - if (proto1->GetId() == proto2->GetId()) + if (sDB2Manager.GetItemDisplayId(proto1->GetId(), bonus->AppearanceModID) == transmogrified->GetDisplayId()) return false; - if (!transmogrified->CanTransmogrify() || !transmogrifier->CanBeTransmogrified()) + if (!transmogrified->CanTransmogrify() || !CanBeTransmogrified(transmogrifier, bonus)) return false; if (proto1->GetInventoryType() == INVTYPE_BAG || @@ -1387,19 +1408,6 @@ bool Item::CanTransmogrifyItemWithItem(Item const* transmogrified, Item const* t return true; } -bool Item::HasStats() const -{ - if (GetItemRandomPropertyId() != 0) - return true; - - ItemTemplate const* proto = GetTemplate(); - for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) - if (proto->GetItemStatValue(i) != 0) - return true; - - return false; -} - // used by mail items, transmog cost, stationeryinfo and others uint32 Item::GetSellPrice(ItemTemplate const* proto, bool& normalSellPrice) { @@ -1784,8 +1792,8 @@ uint32 Item::GetVisibleEntry() const uint32 Item::GetVisibleAppearanceModId() const { - if (uint32 transmogMod = GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD)) - return transmogMod; + if (GetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID)) + return GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD); return GetAppearanceModId(); } @@ -1823,6 +1831,21 @@ void BonusData::Initialize(ItemTemplate const* proto) AppearanceModID = 0; } +void BonusData::Initialize(WorldPackets::Item::ItemInstance const& itemInstance) +{ + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemInstance.ItemID); + if (!proto) + return; + + Initialize(proto); + + if (itemInstance.ItemBonus) + for (uint32 bonusListID : itemInstance.ItemBonus->BonusListIDs) + if (DB2Manager::ItemBonusList const* bonuses = sDB2Manager.GetItemBonusList(bonusListID)) + for (ItemBonusEntry const* bonus : *bonuses) + AddBonus(bonus->Type, bonus->Value); +} + void BonusData::AddBonus(uint32 type, int32 const (&values)[2]) { switch (type) diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 7d03a0a68eb..f81c72c0f98 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -28,6 +28,13 @@ class SpellInfo; class Bag; class Unit; +namespace WorldPackets +{ + namespace Item + { + struct ItemInstance; + } +} struct ItemSetEffect { @@ -242,6 +249,7 @@ struct BonusData uint32 AppearanceModID; void Initialize(ItemTemplate const* proto); + void Initialize(WorldPackets::Item::ItemInstance const& itemInstance); void AddBonus(uint32 type, int32 const (&values)[2]); }; @@ -256,6 +264,7 @@ class Item : public Object virtual bool Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owner); ItemTemplate const* GetTemplate() const; + BonusData const* GetBonus() const { return &_bonusData; } ObjectGuid GetOwnerGUID() const { return GetGuidValue(ITEM_FIELD_OWNER); } void SetOwnerGUID(ObjectGuid guid) { SetGuidValue(ITEM_FIELD_OWNER, guid); } @@ -369,7 +378,6 @@ class Item : public Object bool hasQuest(uint32 quest_id) const override { return GetTemplate()->GetStartQuest() == quest_id; } bool hasInvolvedQuest(uint32 /*quest_id*/) const override { return false; } - bool HasStats() const; bool IsPotion() const { return GetTemplate()->IsPotion(); } bool IsVellum() const { return GetTemplate()->IsVellum(); } bool IsConjuredConsumable() const { return GetTemplate()->IsConjuredConsumable(); } @@ -411,9 +419,11 @@ class Item : public Object uint32 GetScriptId() const { return GetTemplate()->ScriptId; } - bool CanBeTransmogrified() const; + static bool CanBeTransmogrified(WorldPackets::Item::ItemInstance const& transmogrifier, BonusData const* bonus); bool CanTransmogrify() const; - static bool CanTransmogrifyItemWithItem(Item const* transmogrified, Item const* transmogrifier); + bool HasStats() const; + static bool HasStats(WorldPackets::Item::ItemInstance const& itemInstance, BonusData const* bonus); + static bool CanTransmogrifyItemWithItem(Item const* transmogrified, WorldPackets::Item::ItemInstance const& transmogrifier, BonusData const* bonus); static uint32 GetSpecialPrice(ItemTemplate const* proto, uint32 minimumPrice = 10000); uint32 GetSpecialPrice(uint32 minimumPrice = 10000) const { return Item::GetSpecialPrice(GetTemplate(), minimumPrice); } diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 9c1afcc3785..b241dac38d0 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -1109,142 +1109,93 @@ void WorldSession::HandleItemRefund(WorldPacket &recvData) GetPlayer()->RefundItem(item); } -void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData) +void WorldSession::HandleTransmogrifyItems(WorldPackets::Item::TransmogrifyItems& transmogrifyItems) { Player* player = GetPlayer(); - - // Read data - uint32 count = recvData.ReadBits(22); - - if (count >= EQUIPMENT_SLOT_END) - { - TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) sent a wrong count (%u) when transmogrifying items.", player->GetGUID().ToString().c_str(), player->GetName().c_str(), count); - recvData.rfinish(); - return; - } - - std::vector<ObjectGuid> itemGuids(count, ObjectGuid()); - std::vector<uint32> newEntries(count, 0); - std::vector<uint32> slots(count, 0); - - for (uint8 i = 0; i < count; ++i) - { - itemGuids[i][0] = recvData.ReadBit(); - itemGuids[i][5] = recvData.ReadBit(); - itemGuids[i][6] = recvData.ReadBit(); - itemGuids[i][2] = recvData.ReadBit(); - itemGuids[i][3] = recvData.ReadBit(); - itemGuids[i][7] = recvData.ReadBit(); - itemGuids[i][4] = recvData.ReadBit(); - itemGuids[i][1] = recvData.ReadBit(); - } - - ObjectGuid npcGuid; - npcGuid[7] = recvData.ReadBit(); - npcGuid[3] = recvData.ReadBit(); - npcGuid[5] = recvData.ReadBit(); - npcGuid[6] = recvData.ReadBit(); - npcGuid[1] = recvData.ReadBit(); - npcGuid[4] = recvData.ReadBit(); - npcGuid[0] = recvData.ReadBit(); - npcGuid[2] = recvData.ReadBit(); - - recvData.FlushBits(); - - for (uint32 i = 0; i < count; ++i) - { - recvData >> newEntries[i]; - - recvData.ReadByteSeq(itemGuids[i][1]); - recvData.ReadByteSeq(itemGuids[i][5]); - recvData.ReadByteSeq(itemGuids[i][0]); - recvData.ReadByteSeq(itemGuids[i][4]); - recvData.ReadByteSeq(itemGuids[i][6]); - recvData.ReadByteSeq(itemGuids[i][7]); - recvData.ReadByteSeq(itemGuids[i][3]); - recvData.ReadByteSeq(itemGuids[i][2]); - - recvData >> slots[i]; - } - - recvData.ReadByteSeq(npcGuid[7]); - recvData.ReadByteSeq(npcGuid[2]); - recvData.ReadByteSeq(npcGuid[5]); - recvData.ReadByteSeq(npcGuid[4]); - recvData.ReadByteSeq(npcGuid[3]); - recvData.ReadByteSeq(npcGuid[1]); - recvData.ReadByteSeq(npcGuid[6]); - recvData.ReadByteSeq(npcGuid[0]); - // Validate - - if (!player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_TRANSMOGRIFIER)) + if (!player->GetNPCIfCanInteractWith(transmogrifyItems.Npc, UNIT_NPC_FLAG_TRANSMOGRIFIER)) { - TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - %s not found or player can't interact with it.", npcGuid.ToString().c_str()); + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - %s not found or player can't interact with it.", transmogrifyItems.Npc.ToString().c_str()); return; } int64 cost = 0; - std::vector<Item*> transmogrifier(count, NULL); - std::vector<Item*> transmogrified(count, NULL); + std::unordered_map<Item*, Item*> transmogItems; + std::unordered_map<Item*, std::pair<VoidStorageItem*, BonusData>> transmogVoidItems; + std::vector<Item*> resetAppearanceItems; - for (uint8 i = 0; i < count; ++i) + for (WorldPackets::Item::TransmogrifyItem const& transmogItem : transmogrifyItems.Items) { // slot of the transmogrified item - if (slots[i] >= EQUIPMENT_SLOT_END) + if (transmogItem.Slot >= EQUIPMENT_SLOT_END) { - TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify %s with a wrong slot (%u) when transmogrifying items.", player->GetGUID().ToString().c_str(), player->GetName().c_str(), itemGuids[i].ToString().c_str(), slots[i]); + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify wrong slot (%u) when transmogrifying items.", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.Slot); return; } // transmogrified item - Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slots[i]); + Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, transmogItem.Slot); if (!itemTransmogrified) { - TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), slots[i]); + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.Slot); return; } - // if not resetting look - Item* itemTransmogrifier = NULL; - if (newEntries[i]) + WorldPackets::Item::ItemInstance itemInstance; + BonusData const* bonus = nullptr; + if (transmogItem.SrcItemGUID) { - // entry of the transmogrifier item - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newEntries[i]); - if (!proto) + // guid of the transmogrifier item + Item* itemTransmogrifier = player->GetItemByGuid(*transmogItem.SrcItemGUID); + if (!itemTransmogrifier) { - TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify to an invalid item (entry: %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), newEntries[i]); + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcItemGUID->ToString().c_str()); return; } + itemInstance.Initialize(itemTransmogrifier); + bonus = itemTransmogrifier->GetBonus(); + transmogItems[itemTransmogrified] = itemTransmogrifier; + } + else if (transmogItem.SrcVoidItemGUID) + { // guid of the transmogrifier item - itemTransmogrifier = player->GetItemByGuid(itemGuids[i]); + uint8 slot; + VoidStorageItem* itemTransmogrifier = player->GetVoidStorageItem(transmogItem.SrcVoidItemGUID->GetCounter(), slot); if (!itemTransmogrifier) { - TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), itemGuids[i].ToString().c_str()); + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid void storage item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcVoidItemGUID->ToString().c_str()); return; } - // entry of transmogrifier and from packet - if (itemTransmogrifier->GetEntry() != newEntries[i]) - { - TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid entry (entry: %u) for %s.", player->GetGUID().ToString().c_str(), player->GetName().c_str(), newEntries[i], itemGuids[i].ToString().c_str()); - return; - } + itemInstance.Initialize(itemTransmogrifier); + std::pair<VoidStorageItem*, BonusData>& transmogData = transmogVoidItems[itemTransmogrified]; + transmogData.first = itemTransmogrifier; + transmogData.second.Initialize(itemInstance); + bonus = &transmogData.second; + } + else + { + resetAppearanceItems.push_back(itemTransmogrified); + continue; + } - // validity of the transmogrification items - if (!Item::CanTransmogrifyItemWithItem(itemTransmogrified, itemTransmogrifier)) - { - TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry()); - return; - } + // entry of transmogrifier and from packet + if (itemInstance != transmogItem.Item) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid item instance data for %s.", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.Item.ItemID, transmogItem.SrcItemGUID->ToString().c_str()); + return; + } - // add cost - cost += itemTransmogrified->GetSpecialPrice(); + // validity of the transmogrification items + if (!Item::CanTransmogrifyItemWithItem(itemTransmogrified, transmogItem.Item, bonus)) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), itemTransmogrified->GetEntry(), transmogItem.Item.ItemID); + return; } - transmogrifier[i] = itemTransmogrifier; - transmogrified[i] = itemTransmogrified; + // add cost + cost += itemTransmogrified->GetSpecialPrice(); } if (cost) // 0 cost if reverting look @@ -1255,34 +1206,44 @@ void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData) } // Everything is fine, proceed - - for (uint8 i = 0; i < count; ++i) + for (auto& transmogPair : transmogItems) { - if (transmogrifier[i]) - { - // Transmogrify - transmogrified[i]->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, newEntries[i]); - player->SetVisibleItemSlot(slots[i], transmogrified[i]); + Item* transmogrified = transmogPair.first; + Item* transmogrifier = transmogPair.second; - transmogrified[i]->UpdatePlayedTime(player); + transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, transmogrifier->GetEntry()); + transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD, transmogrifier->GetAppearanceModId()); + player->SetVisibleItemSlot(transmogrified->GetSlot(), transmogrified); - transmogrified[i]->SetOwnerGUID(player->GetGUID()); - transmogrified[i]->SetNotRefundable(player); - transmogrified[i]->ClearSoulboundTradeable(player); + transmogrified->SetNotRefundable(player); + transmogrified->ClearSoulboundTradeable(player); - if (transmogrifier[i]->GetTemplate()->GetBonding() == BIND_WHEN_EQUIPED || transmogrifier[i]->GetTemplate()->GetBonding() == BIND_WHEN_USE) - transmogrifier[i]->SetBinding(true); + transmogrifier->SetNotRefundable(player); + transmogrifier->ClearSoulboundTradeable(player); - transmogrifier[i]->SetOwnerGUID(player->GetGUID()); - transmogrifier[i]->SetNotRefundable(player); - transmogrifier[i]->ClearSoulboundTradeable(player); - } - else - { - // Reset - transmogrified[i]->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, 0); - player->SetVisibleItemSlot(slots[i], transmogrified[i]); - } + if (transmogrifier->GetTemplate()->GetBonding() == BIND_WHEN_EQUIPED || transmogrifier->GetTemplate()->GetBonding() == BIND_WHEN_USE) + transmogrifier->SetBinding(true); + } + + for (auto& transmogVoirPair : transmogVoidItems) + { + Item* transmogrified = transmogVoirPair.first; + VoidStorageItem* transmogrifier = transmogVoirPair.second.first; + BonusData& bonus = transmogVoirPair.second.second; + + transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, transmogrifier->ItemEntry); + transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD, bonus.AppearanceModID); + player->SetVisibleItemSlot(transmogrified->GetSlot(), transmogrified); + + transmogrified->SetNotRefundable(player); + transmogrified->ClearSoulboundTradeable(player); + } + + for (Item* item : resetAppearanceItems) + { + item->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, 0); + item->SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD, 0); + player->SetVisibleItemSlot(item->GetSlot(), item); } } diff --git a/src/server/game/Handlers/VoidStorageHandler.cpp b/src/server/game/Handlers/VoidStorageHandler.cpp index 95d117227ad..ba8ad1dc056 100644 --- a/src/server/game/Handlers/VoidStorageHandler.cpp +++ b/src/server/game/Handlers/VoidStorageHandler.cpp @@ -52,7 +52,7 @@ void WorldSession::HandleVoidStorageUnlock(WorldPackets::VoidStorage::UnlockVoid void WorldSession::HandleVoidStorageQuery(WorldPackets::VoidStorage::QueryVoidStorage& queryVoidStorage) { - Creature* unit = _player->GetNPCIfCanInteractWith(queryVoidStorage.Npc, UNIT_NPC_FLAG_VAULTKEEPER); + Creature* unit = _player->GetNPCIfCanInteractWith(queryVoidStorage.Npc, UNIT_NPC_FLAG_TRANSMOGRIFIER | UNIT_NPC_FLAG_VAULTKEEPER); if (!unit) { TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageQuery - %s not found or player can't interact with it.", queryVoidStorage.Npc.ToString().c_str()); diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp index 7d54ebe3ec6..80bafbba104 100644 --- a/src/server/game/Server/Packets/ItemPackets.cpp +++ b/src/server/game/Server/Packets/ItemPackets.cpp @@ -18,6 +18,17 @@ #include "ItemPackets.h" #include "Player.h" +bool WorldPackets::Item::ItemBonusInstanceData::operator==(ItemBonusInstanceData const& r) const +{ + if (Context != r.Context) + return false; + + if (BonusListIDs.size() != r.BonusListIDs.size()) + return false; + + return std::is_permutation(BonusListIDs.begin(), BonusListIDs.end(), r.BonusListIDs.begin()); +} + void WorldPackets::Item::BuyBackItem::Read() { _worldPacket >> VendorGUID @@ -228,6 +239,23 @@ void WorldPackets::Item::ItemInstance::Initialize(::VoidStorageItem const* voidI } } +bool WorldPackets::Item::ItemInstance::operator==(ItemInstance const& r) const +{ + if (ItemID != r.ItemID || RandomPropertiesID != r.RandomPropertiesID || RandomPropertiesSeed != r.RandomPropertiesSeed) + return false; + + if (ItemBonus.is_initialized() != r.ItemBonus.is_initialized() || Modifications.is_initialized() != r.Modifications.is_initialized()) + return false; + + if (Modifications.is_initialized() && *Modifications != *r.Modifications) + return false; + + if (ItemBonus.is_initialized() && *ItemBonus != *r.ItemBonus) + return false; + + return true; +} + WorldPacket const* WorldPackets::Item::InventoryChangeFailure::Write() { _worldPacket << int8(BagResult); @@ -405,3 +433,31 @@ WorldPacket const* WorldPackets::Item::ItemEnchantTimeUpdate::Write() return &_worldPacket; } + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Item::TransmogrifyItem& transmogItem) +{ + if (data.ReadBit()) + transmogItem.SrcItemGUID = boost::in_place(); + + if (data.ReadBit()) + transmogItem.SrcVoidItemGUID = boost::in_place(); + + data >> transmogItem.Item; + data >> transmogItem.Slot; + + if (transmogItem.SrcItemGUID.is_initialized()) + data >> *transmogItem.SrcItemGUID; + + if (transmogItem.SrcVoidItemGUID.is_initialized()) + data >> *transmogItem.SrcVoidItemGUID; + + return data; +} + +void WorldPackets::Item::TransmogrifyItems::Read() +{ + Items.resize(_worldPacket.read<uint32>()); + _worldPacket >> Npc; + for (TransmogrifyItem& item : Items) + _worldPacket >> item; +} diff --git a/src/server/game/Server/Packets/ItemPackets.h b/src/server/game/Server/Packets/ItemPackets.h index d179f03b041..943a681edbe 100644 --- a/src/server/game/Server/Packets/ItemPackets.h +++ b/src/server/game/Server/Packets/ItemPackets.h @@ -32,6 +32,9 @@ namespace WorldPackets { uint8 Context = 0; std::vector<int32> BonusListIDs; + + bool operator==(ItemBonusInstanceData const& r) const; + bool operator!=(ItemBonusInstanceData const& r) const { return !(*this == r); } }; struct ItemInstance @@ -45,6 +48,9 @@ namespace WorldPackets uint32 RandomPropertiesID = 0; Optional<ItemBonusInstanceData> ItemBonus; Optional<CompactArray<int32>> Modifications; + + bool operator==(ItemInstance const& r) const; + bool operator!=(ItemInstance const& r) const { return !(*this == r); } }; class BuyBackItem final : public ClientPacket @@ -398,6 +404,30 @@ namespace WorldPackets uint32 Slot = 0; }; + struct TransmogrifyItem + { + Optional<ObjectGuid> SrcItemGUID; + Optional<ObjectGuid> SrcVoidItemGUID; + ItemInstance Item; + uint32 Slot = 0; + }; + + class TransmogrifyItems final : public ClientPacket + { + public: + enum + { + MAX_TRANSMOGRIFY_ITEMS = 11 + }; + + TransmogrifyItems(WorldPacket&& packet) : ClientPacket(CMSG_TRANSMOGRIFY_ITEMS, std::move(packet)) { } + + void Read() override; + + ObjectGuid Npc; + Array<TransmogrifyItem, MAX_TRANSMOGRIFY_ITEMS> Items; + }; + ByteBuffer& operator>>(ByteBuffer& data, InvUpdate& invUpdate); } } diff --git a/src/server/game/Server/Packets/PacketUtilities.h b/src/server/game/Server/Packets/PacketUtilities.h index 4837ee9e69c..4f39e264efb 100644 --- a/src/server/game/Server/Packets/PacketUtilities.h +++ b/src/server/game/Server/Packets/PacketUtilities.h @@ -178,6 +178,16 @@ namespace WorldPackets _contents.clear(); } + bool operator==(CompactArray const& r) const + { + if (_mask != r._mask) + return false; + + return _contents == r._contents; + } + + bool operator!=(CompactArray const& r) const { return !(*this == r); } + private: uint32 _mask; std::vector<T> _contents; diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 4dcf5fe9bc4..88fdbdc3305 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -789,7 +789,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_TOY_SET_FAVORITE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TRAINER_BUY_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::TrainerBuySpell, &WorldSession::HandleTrainerBuySpellOpcode); DEFINE_HANDLER(CMSG_TRAINER_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleTrainerListOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_TRANSMOGRIFY_ITEMS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTransmogrifyItems ); + DEFINE_HANDLER(CMSG_TRANSMOGRIFY_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::TransmogrifyItems, &WorldSession::HandleTransmogrifyItems); DEFINE_HANDLER(CMSG_TURN_IN_PETITION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::TurnInPetition, &WorldSession::HandleTurnInPetition); DEFINE_HANDLER(CMSG_TUTORIAL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::TutorialSetFlag, &WorldSession::HandleTutorialFlag); DEFINE_HANDLER(CMSG_TWITTER_CHECK_STATUS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 8d31aefe48a..107a4350af6 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -319,6 +319,7 @@ namespace WorldPackets class SwapItem; class WrapItem; class CancelTempEnchantment; + class TransmogrifyItems; } namespace Loot @@ -1519,7 +1520,7 @@ class WorldSession void SendVoidStorageTransferResult(VoidTransferError result); // Transmogrification - void HandleTransmogrifyItems(WorldPacket& recvData); + void HandleTransmogrifyItems(WorldPackets::Item::TransmogrifyItems& transmogrifyItems); // Miscellaneous void HandleSpellClick(WorldPackets::Spells::SpellClick& spellClick); |