diff options
-rw-r--r-- | src/server/game/Handlers/AuctionHouseHandler.cpp | 568 | ||||
-rw-r--r-- | src/server/game/Server/Packets/AuctionHousePackets.cpp | 193 | ||||
-rw-r--r-- | src/server/game/Server/Packets/AuctionHousePackets.h | 154 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 11 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.h | 25 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 24 |
6 files changed, 968 insertions, 7 deletions
diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index 04845eb65c1..15149fd7f53 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -33,6 +33,162 @@ #include "World.h" #include <sstream> +void WorldSession::HandleAuctionBrowseQuery(WorldPackets::AuctionHouse::AuctionBrowseQuery& browseQuery) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, browseQuery.TaintedBy.has_value()); + if (throttle.Throttled) + return; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(browseQuery.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionListItems - {} not found or you can't interact with him.", browseQuery.Auctioneer.ToString()); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction()); + + TC_LOG_DEBUG("auctionHouse", "Auctionhouse search {}, searchedname: {}, levelmin: {}, levelmax: {}, filters: {}", + browseQuery.Auctioneer.ToString(), browseQuery.Name, browseQuery.MinLevel, browseQuery.MaxLevel, AsUnderlyingType(browseQuery.Filters)); + + std::wstring name; + if (!Utf8toWStr(browseQuery.Name, name)) + return; + + Optional<AuctionSearchClassFilters> classFilters; + + WorldPackets::AuctionHouse::AuctionListBucketsResult listBucketsResult; + if (!browseQuery.ItemClassFilters.empty()) + { + classFilters.emplace(); + + for (auto const& classFilter : browseQuery.ItemClassFilters) + { + if (!classFilter.SubClassFilters.empty()) + { + for (auto const& subClassFilter : classFilter.SubClassFilters) + { + if (classFilter.ItemClass < MAX_ITEM_CLASS) + { + classFilters->Classes[classFilter.ItemClass].SubclassMask |= 1 << subClassFilter.ItemSubclass; + if (subClassFilter.ItemSubclass < MAX_ITEM_SUBCLASS_TOTAL) + classFilters->Classes[classFilter.ItemClass].InvTypes[subClassFilter.ItemSubclass] = subClassFilter.InvTypeMask; + } + } + } + else + classFilters->Classes[classFilter.ItemClass].SubclassMask = AuctionSearchClassFilters::FILTER_SKIP_SUBCLASS; + } + } + + auctionHouse->BuildListBuckets(listBucketsResult, _player, + name, browseQuery.MinLevel, browseQuery.MaxLevel, browseQuery.Filters, classFilters, + browseQuery.KnownPets, browseQuery.MaxPetLevel, browseQuery.Offset, browseQuery.Sorts); + + listBucketsResult.BrowseMode = AuctionHouseBrowseMode::Search; + listBucketsResult.DesiredDelay = uint32(throttle.DelayUntilNext.count()); + SendPacket(listBucketsResult.Write()); +} + +void WorldSession::HandleAuctionCancelCommoditiesPurchase(WorldPackets::AuctionHouse::AuctionCancelCommoditiesPurchase& cancelCommoditiesPurchase) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, cancelCommoditiesPurchase.TaintedBy.has_value(), AuctionCommand::PlaceBid); + if (throttle.Throttled) + return; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(cancelCommoditiesPurchase.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionCancelCommoditiesPurchase - {} not found or you can't interact with him.", + cancelCommoditiesPurchase.Auctioneer.ToString()); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction()); + auctionHouse->CancelCommodityQuote(_player->GetGUID()); +} + +void WorldSession::HandleAuctionConfirmCommoditiesPurchase(WorldPackets::AuctionHouse::AuctionConfirmCommoditiesPurchase& confirmCommoditiesPurchase) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, confirmCommoditiesPurchase.TaintedBy.has_value(), AuctionCommand::PlaceBid); + if (throttle.Throttled) + return; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(confirmCommoditiesPurchase.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionConfirmCommoditiesPurchase - {} not found or you can't interact with him.", confirmCommoditiesPurchase.Auctioneer.ToString()); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction()); + + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + if (auctionHouse->BuyCommodity(trans, _player, confirmCommoditiesPurchase.ItemID, confirmCommoditiesPurchase.Quantity, throttle.DelayUntilNext)) + { + AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(trans)).AfterComplete([this, buyerGuid = _player->GetGUID(), throttle](bool success) + { + if (GetPlayer() && GetPlayer()->GetGUID() == buyerGuid) + { + if (success) + { + GetPlayer()->UpdateCriteria(CriteriaType::AuctionsWon, 1); + SendAuctionCommandResult(0, AuctionCommand::PlaceBid, AuctionResult::Ok, throttle.DelayUntilNext); + } + else + SendAuctionCommandResult(0, AuctionCommand::PlaceBid, AuctionResult::CommodityPurchaseFailed, throttle.DelayUntilNext); + } + }); + } +} + +void WorldSession::HandleAuctionGetCommodityQuote(WorldPackets::AuctionHouse::AuctionGetCommodityQuote& getCommodityQuote) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, getCommodityQuote.TaintedBy.has_value(), AuctionCommand::PlaceBid); + if (throttle.Throttled) + return; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(getCommodityQuote.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionStartCommoditiesPurchase - {} not found or you can't interact with him.", + getCommodityQuote.Auctioneer.ToString()); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction()); + + WorldPackets::AuctionHouse::AuctionGetCommodityQuoteResult commodityQuoteResult; + + if (CommodityQuote const* quote = auctionHouse->CreateCommodityQuote(_player, getCommodityQuote.ItemID, getCommodityQuote.Quantity)) + { + commodityQuoteResult.TotalPrice = quote->TotalPrice; + commodityQuoteResult.Quantity = quote->Quantity; + commodityQuoteResult.QuoteDuration = std::chrono::duration_cast<Milliseconds>(quote->ValidTo - GameTime::Now()); + } + + commodityQuoteResult.ItemID = getCommodityQuote.ItemID; + commodityQuoteResult.DesiredDelay = uint32(throttle.DelayUntilNext.count()); + + SendPacket(commodityQuoteResult.Write()); +} + void WorldSession::HandleAuctionHelloOpcode(WorldPackets::AuctionHouse::AuctionHelloRequest& hello) { Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(hello.Guid, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); @@ -49,6 +205,149 @@ void WorldSession::HandleAuctionHelloOpcode(WorldPackets::AuctionHouse::AuctionH SendAuctionHello(hello.Guid, unit); } +void WorldSession::HandleAuctionListBiddedItems(WorldPackets::AuctionHouse::AuctionListBiddedItems& listBiddedItems) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, listBiddedItems.TaintedBy.has_value()); + if (throttle.Throttled) + return; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(listBiddedItems.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionListBidderItems - {} not found or you can't interact with him.", listBiddedItems.Auctioneer.ToString()); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction()); + + WorldPackets::AuctionHouse::AuctionListBiddedItemsResult result; + + Player* player = GetPlayer(); + auctionHouse->BuildListBiddedItems(result, player, listBiddedItems.Offset, listBiddedItems.Sorts); + result.DesiredDelay = uint32(throttle.DelayUntilNext.count()); + SendPacket(result.Write()); +} + +void WorldSession::HandleAuctionListBucketsByBucketKeys(WorldPackets::AuctionHouse::AuctionListBucketsByBucketKeys& listBucketsByBucketKeys) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, listBucketsByBucketKeys.TaintedBy.has_value()); + if (throttle.Throttled) + return; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(listBucketsByBucketKeys.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionListBucketsByBucketKeys - {} not found or you can't interact with him.", + listBucketsByBucketKeys.Auctioneer.ToString()); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction()); + + WorldPackets::AuctionHouse::AuctionListBucketsResult listBucketsResult; + + auctionHouse->BuildListBuckets(listBucketsResult, _player, listBucketsByBucketKeys.BucketKeys, listBucketsByBucketKeys.Sorts); + + listBucketsResult.BrowseMode = AuctionHouseBrowseMode::SpecificKeys; + listBucketsResult.DesiredDelay = uint32(throttle.DelayUntilNext.count()); + SendPacket(listBucketsResult.Write()); +} + +void WorldSession::HandleAuctionListItemsByBucketKey(WorldPackets::AuctionHouse::AuctionListItemsByBucketKey& listItemsByBucketKey) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, listItemsByBucketKey.TaintedBy.has_value()); + if (throttle.Throttled) + return; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(listItemsByBucketKey.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionListItemsByBucketKey - {} not found or you can't interact with him.", listItemsByBucketKey.Auctioneer.ToString()); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction()); + + WorldPackets::AuctionHouse::AuctionListItemsResult listItemsResult; + listItemsResult.DesiredDelay = uint32(throttle.DelayUntilNext.count()); + listItemsResult.BucketKey = listItemsByBucketKey.BucketKey; + ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(listItemsByBucketKey.BucketKey.ItemID); + listItemsResult.ListType = itemTemplate && itemTemplate->GetMaxStackSize() > 1 ? AuctionHouseListType::Commodities : AuctionHouseListType::Items; + + auctionHouse->BuildListAuctionItems(listItemsResult, _player, listItemsByBucketKey.BucketKey, listItemsByBucketKey.Offset, listItemsByBucketKey.Sorts); + + SendPacket(listItemsResult.Write()); +} + +void WorldSession::HandleAuctionListItemsByItemID(WorldPackets::AuctionHouse::AuctionListItemsByItemID& listItemsByItemID) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, listItemsByItemID.TaintedBy.has_value()); + if (throttle.Throttled) + return; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(listItemsByItemID.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionListItemsByItemID - {} not found or you can't interact with him.", listItemsByItemID.Auctioneer.ToString()); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction()); + + WorldPackets::AuctionHouse::AuctionListItemsResult listItemsResult; + listItemsResult.DesiredDelay = uint32(throttle.DelayUntilNext.count()); + listItemsResult.BucketKey.ItemID = listItemsByItemID.ItemID; + ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(listItemsByItemID.ItemID); + listItemsResult.ListType = itemTemplate && itemTemplate->GetMaxStackSize() > 1 ? AuctionHouseListType::Commodities : AuctionHouseListType::Items; + + auctionHouse->BuildListAuctionItems(listItemsResult, _player, listItemsByItemID.ItemID, listItemsByItemID.Offset, listItemsByItemID.Sorts); + + SendPacket(listItemsResult.Write()); +} + +//this void sends player info about his auctions +void WorldSession::HandleAuctionListOwnedItems(WorldPackets::AuctionHouse::AuctionListOwnedItems& listOwnedItems) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, listOwnedItems.TaintedBy.has_value()); + if (throttle.Throttled) + return; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(listOwnedItems.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionListOwnerItems - {} not found or you can't interact with him.", listOwnedItems.Auctioneer.ToString()); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction()); + + WorldPackets::AuctionHouse::AuctionListOwnedItemsResult result; + + auctionHouse->BuildListOwnedItems(result, _player, listOwnedItems.Offset, listOwnedItems.Sorts); + result.DesiredDelay = uint32(throttle.DelayUntilNext.count()); + SendPacket(result.Write()); +} + // this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid(WorldPackets::AuctionHouse::AuctionPlaceBid& placeBid) { @@ -275,6 +574,247 @@ void WorldSession::HandleAuctionReplicateItems(WorldPackets::AuctionHouse::Aucti SendPacket(response.Write()); } +void WorldSession::SendAuctionFavoriteList() +{ + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_FAVORITE_AUCTIONS); + stmt->setUInt64(0, _player->GetGUID().GetCounter()); + GetQueryProcessor().AddCallback(CharacterDatabase.AsyncQuery(stmt)).WithPreparedCallback([this](PreparedQueryResult favoriteAuctionResult) + { + WorldPackets::AuctionHouse::AuctionFavoriteList favoriteItems; + if (favoriteAuctionResult) + { + favoriteItems.Items.reserve(favoriteAuctionResult->GetRowCount()); + + do + { + Field* fields = favoriteAuctionResult->Fetch(); + + WorldPackets::AuctionHouse::AuctionFavoriteInfo& item = favoriteItems.Items.emplace_back(); + item.Order = fields[0].GetUInt32(); + item.ItemID = fields[1].GetUInt32(); + item.ItemLevel = fields[2].GetUInt32(); + item.BattlePetSpeciesID = fields[3].GetUInt32(); + item.SuffixItemNameDescriptionID = fields[4].GetUInt32(); + + } while (favoriteAuctionResult->NextRow()); + + } + SendPacket(favoriteItems.Write()); + }); +} + +void WorldSession::HandleAuctionSellCommodity(WorldPackets::AuctionHouse::AuctionSellCommodity& sellCommodity) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, sellCommodity.TaintedBy.has_value(), AuctionCommand::SellItem); + if (throttle.Throttled) + return; + + if (!sellCommodity.UnitPrice || sellCommodity.UnitPrice > MAX_MONEY_AMOUNT) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Player {} {} attempted to sell item with invalid price.", _player->GetName(), _player->GetGUID().ToString()); + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::DatabaseError, throttle.DelayUntilNext); + return; + } + + // auction house does not deal with copper + if (sellCommodity.UnitPrice % SILVER) + { + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::DatabaseError, throttle.DelayUntilNext); + return; + } + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(sellCommodity.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER, UNIT_NPC_FLAG_2_NONE); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit {} not found or you can't interact with him.", sellCommodity.Auctioneer.ToString()); + return; + } + + uint32 houseId = 0; + AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->GetFaction(), &houseId); + if (!auctionHouseEntry) + { + TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit {} has wrong faction.", sellCommodity.Auctioneer.ToString()); + return; + } + + switch (sellCommodity.RunTime) + { + case 1 * MIN_AUCTION_TIME / MINUTE: + case 2 * MIN_AUCTION_TIME / MINUTE: + case 4 * MIN_AUCTION_TIME / MINUTE: + break; + default: + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::AuctionHouseBusy, throttle.DelayUntilNext); + return; + } + + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // find all items for sale + uint64 totalCount = 0; + std::unordered_map<ObjectGuid, std::pair<Item*, uint64>> items2; + + for (WorldPackets::AuctionHouse::AuctionItemForSale const& itemForSale : sellCommodity.Items) + { + Item* item = _player->GetItemByGuid(itemForSale.Guid); + if (!item) + { + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::ItemNotFound, throttle.DelayUntilNext); + return; + } + + if (item->GetTemplate()->GetMaxStackSize() == 1) + { + // not commodity, must use different packet + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::ItemNotFound, throttle.DelayUntilNext); + return; + } + + // verify that all items belong to the same bucket + if (!items2.empty() && AuctionsBucketKey::ForItem(item) != AuctionsBucketKey::ForItem(items2.begin()->second.first)) + { + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::ItemNotFound, throttle.DelayUntilNext); + return; + } + + if (sAuctionMgr->GetAItem(item->GetGUID()) || !item->CanBeTraded() || item->IsNotEmptyBag() || + item->GetTemplate()->HasFlag(ITEM_FLAG_CONJURED) || *item->m_itemData->Expiration || + item->GetCount() < itemForSale.UseCount) + { + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::DatabaseError, throttle.DelayUntilNext); + return; + } + + std::pair<Item*, uint64>& soldItem = items2[item->GetGUID()]; + soldItem.first = item; + soldItem.second += itemForSale.UseCount; + if (item->GetCount() < soldItem.second) + { + // check that we have enough of this item to sell + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::ItemNotFound, throttle.DelayUntilNext); + return; + } + + totalCount += itemForSale.UseCount; + } + + if (!totalCount) + { + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::DatabaseError, throttle.DelayUntilNext); + return; + } + + Seconds auctionTime = Seconds(int64(std::chrono::duration_cast<Seconds>(Minutes(sellCommodity.RunTime)).count() * double(sWorld->getRate(RATE_AUCTION_TIME)))); + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction()); + + uint64 deposit = AuctionHouseMgr::GetCommodityAuctionDeposit(items2.begin()->second.first->GetTemplate(), Minutes(sellCommodity.RunTime), totalCount); + if (!_player->HasEnoughMoney(deposit)) + { + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::NotEnoughMoney, throttle.DelayUntilNext); + return; + } + + uint32 auctionId = sObjectMgr->GenerateAuctionID(); + AuctionPosting auction; + auction.Id = auctionId; + auction.Owner = _player->GetGUID(); + auction.OwnerAccount = GetAccountGUID(); + auction.BuyoutOrUnitPrice = sellCommodity.UnitPrice; + auction.Deposit = deposit; + auction.StartTime = GameTime::GetSystemTime(); + auction.EndTime = auction.StartTime + auctionTime; + + // keep track of what was cloned to undo/modify counts later + std::unordered_map<Item* /*original*/, std::unique_ptr<Item> /*clone*/> clones; + for (std::pair<ObjectGuid const, std::pair<Item*, uint64>>& it : items2) + { + Item* itemForSale; + if (it.second.first->GetCount() != it.second.second) + { + itemForSale = it.second.first->CloneItem(it.second.second, _player); + if (!itemForSale) + { + TC_LOG_ERROR("network", "CMSG_AUCTION_SELL_COMMODITY: Could not create clone of item {}", it.second.first->GetEntry()); + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::DatabaseError, throttle.DelayUntilNext); + return; + } + + clones.emplace(it.second.first, itemForSale); + } + } + + if (!sAuctionMgr->PendingAuctionAdd(_player, auctionHouse->GetAuctionHouseId(), auction.Id, auction.Deposit)) + { + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::NotEnoughMoney, throttle.DelayUntilNext); + return; + } + + TC_LOG_INFO("network", "CMSG_AUCTION_SELL_COMMODITY: {} {} is selling item {} {} to auctioneer {} with count {} with with unit price {} and with time {} (in sec) in auctionhouse {}", + _player->GetGUID().ToString(), _player->GetName(), items2.begin()->second.first->GetNameForLocaleIdx(sWorld->GetDefaultDbcLocale()), + ([&items2]() + { + std::stringstream ss; + auto itr = items2.begin(); + ss << (itr++)->first.ToString(); + for (; itr != items2.end(); ++itr) + ss << ',' << itr->first.ToString(); + return ss.str(); + }()).c_str(), + creature->GetGUID().ToString().c_str(), totalCount, sellCommodity.UnitPrice, uint32(auctionTime.count()), auctionHouse->GetAuctionHouseId()); + + if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + Item* logItem = items2.begin()->second.first; + sLog->OutCommand(GetAccountId(), "GM {} (Account: {}) create auction: {} (Entry: {} Count: {})", + GetPlayerName(), GetAccountId(), logItem->GetNameForLocaleIdx(sWorld->GetDefaultDbcLocale()), logItem->GetEntry(), totalCount); + } + + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + + for (std::pair<ObjectGuid const, std::pair<Item*, uint64>> const& it : items2) + { + Item* itemForSale = it.second.first; + auto cloneItr = clones.find(it.second.first); + if (cloneItr != clones.end()) + { + Item* original = itemForSale; + original->SetCount(original->GetCount() - uint32(it.second.second)); + original->SetState(ITEM_CHANGED, _player); + _player->ItemRemovedQuestCheck(original->GetEntry(), uint32(it.second.second)); + original->SaveToDB(trans); + + itemForSale = cloneItr->second.release(); + } + else + { + _player->MoveItemFromInventory(itemForSale->GetBagSlot(), itemForSale->GetSlot(), true); + itemForSale->DeleteFromInventoryDB(trans); + } + + itemForSale->SaveToDB(trans); + auction.Items.push_back(itemForSale); + } + + auctionHouse->AddAuction(trans, std::move(auction)); + _player->SaveInventoryAndGoldToDB(trans); + + AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(trans)).AfterComplete([this, auctionId, auctionPlayerGuid = _player->GetGUID(), throttle](bool success) + { + if (GetPlayer() && GetPlayer()->GetGUID() == auctionPlayerGuid) + { + if (success) + { + GetPlayer()->UpdateCriteria(CriteriaType::ItemsPostedAtAuction, 1); + SendAuctionCommandResult(auctionId, AuctionCommand::SellItem, AuctionResult::Ok, throttle.DelayUntilNext); + } + else + SendAuctionCommandResult(0, AuctionCommand::SellItem, AuctionResult::DatabaseError, throttle.DelayUntilNext); + } + }); +} + void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSellItem& sellItem) { AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, sellItem.TaintedBy.has_value(), AuctionCommand::SellItem); @@ -423,6 +963,34 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell }); } +void WorldSession::HandleAuctionSetFavoriteItem(WorldPackets::AuctionHouse::AuctionSetFavoriteItem& setFavoriteItem) +{ + AuctionThrottleResult throttle = sAuctionMgr->CheckThrottle(_player, false); + if (throttle.Throttled) + return; + + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_FAVORITE_AUCTION); + stmt->setUInt64(0, _player->GetGUID().GetCounter()); + stmt->setUInt32(1, setFavoriteItem.Item.Order); + trans->Append(stmt); + + if (!setFavoriteItem.IsNotFavorite) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_FAVORITE_AUCTION); + stmt->setUInt64(0, _player->GetGUID().GetCounter()); + stmt->setUInt32(1, setFavoriteItem.Item.Order); + stmt->setUInt32(2, setFavoriteItem.Item.ItemID); + stmt->setUInt32(3, setFavoriteItem.Item.ItemLevel); + stmt->setUInt32(4, setFavoriteItem.Item.BattlePetSpeciesID); + stmt->setUInt32(5, setFavoriteItem.Item.SuffixItemNameDescriptionID); + trans->Append(stmt); + } + + CharacterDatabase.CommitTransaction(trans); +} + //this void causes that auction window is opened void WorldSession::SendAuctionHello(ObjectGuid guid, Unit const* unit) { diff --git a/src/server/game/Server/Packets/AuctionHousePackets.cpp b/src/server/game/Server/Packets/AuctionHousePackets.cpp index 1f4913779f1..e1b1ed5a0ac 100644 --- a/src/server/game/Server/Packets/AuctionHousePackets.cpp +++ b/src/server/game/Server/Packets/AuctionHousePackets.cpp @@ -274,11 +274,168 @@ ByteBuffer& operator<<(ByteBuffer& data, AuctionBidderNotification const& bidder return data; } +void AuctionBrowseQuery::Read() +{ + _worldPacket >> Auctioneer; + _worldPacket >> Offset; + _worldPacket >> MinLevel; + _worldPacket >> MaxLevel; + _worldPacket >> Unused1007_1; + _worldPacket >> Unused1007_2; + _worldPacket >> As<uint32>(Filters); + + uint32 knownPetsSize = _worldPacket.read<uint32>(); + uint32 const sizeLimit = sBattlePetSpeciesStore.GetNumRows() / (sizeof(decltype(KnownPets)::value_type) * 8) + 1; + if (knownPetsSize >= sizeLimit) + throw PacketArrayMaxCapacityException(knownPetsSize, sizeLimit); + + KnownPets.resize(knownPetsSize); + _worldPacket >> MaxPetLevel; + for (uint8& knownPetMask : KnownPets) + _worldPacket >> knownPetMask; + + if (_worldPacket.ReadBit()) + TaintedBy.emplace(); + + uint32 nameLength = _worldPacket.ReadBits(8); + ItemClassFilters.resize(_worldPacket.ReadBits(3)); + Sorts.resize(_worldPacket.ReadBits(2)); + + for (AuctionSortDef& sortDef : Sorts) + _worldPacket >> sortDef; + + if (TaintedBy) + _worldPacket >> *TaintedBy; + + Name = _worldPacket.ReadString(nameLength); + for (AuctionListFilterClass& filterClass : ItemClassFilters) + _worldPacket >> filterClass; +} + +void AuctionCancelCommoditiesPurchase::Read() +{ + _worldPacket >> Auctioneer; + if (_worldPacket.ReadBit()) + { + TaintedBy.emplace(); + _worldPacket >> *TaintedBy; + } +} + +void AuctionConfirmCommoditiesPurchase::Read() +{ + _worldPacket >> Auctioneer; + _worldPacket >> ItemID; + _worldPacket >> Quantity; + if (_worldPacket.ReadBit()) + { + TaintedBy.emplace(); + _worldPacket >> *TaintedBy; + } +} + void AuctionHelloRequest::Read() { _worldPacket >> Guid; } +void AuctionListBiddedItems::Read() +{ + _worldPacket >> Auctioneer; + _worldPacket >> Offset; + + if (_worldPacket.ReadBit()) + TaintedBy.emplace(); + + AuctionIDs.resize(_worldPacket.ReadBits(7)); + Sorts.resize(_worldPacket.ReadBits(2)); + + for (AuctionSortDef& sortDef : Sorts) + _worldPacket >> sortDef; + + if (TaintedBy) + _worldPacket >> *TaintedBy; + + for (uint32& auctionID : AuctionIDs) + _worldPacket >> auctionID; +} + +void AuctionListBucketsByBucketKeys::Read() +{ + _worldPacket >> Auctioneer; + + if (_worldPacket.ReadBit()) + TaintedBy.emplace(); + + BucketKeys.resize(_worldPacket.ReadBits(7)); + Sorts.resize(_worldPacket.ReadBits(2)); + + for (AuctionSortDef& sortDef : Sorts) + _worldPacket >> sortDef; + + if (TaintedBy) + _worldPacket >> *TaintedBy; + + for (AuctionBucketKey& bucketKey : BucketKeys) + _worldPacket >> bucketKey; +} + +void AuctionListItemsByBucketKey::Read() +{ + _worldPacket >> Auctioneer; + _worldPacket >> Offset; + _worldPacket >> Unknown830; + + if (_worldPacket.ReadBit()) + TaintedBy.emplace(); + + Sorts.resize(_worldPacket.ReadBits(2)); + + for (AuctionSortDef& sortDef : Sorts) + _worldPacket >> sortDef; + + _worldPacket >> BucketKey; + + if (TaintedBy) + _worldPacket >> *TaintedBy; +} + +void AuctionListItemsByItemID::Read() +{ + _worldPacket >> Auctioneer; + _worldPacket >> ItemID; + _worldPacket >> SuffixItemNameDescriptionID; + _worldPacket >> Offset; + + if (_worldPacket.ReadBit()) + TaintedBy.emplace(); + + Sorts.resize(_worldPacket.ReadBits(2)); + + for (AuctionSortDef& sortDef : Sorts) + _worldPacket >> sortDef; + + if (TaintedBy) + _worldPacket >> *TaintedBy; +} + +void AuctionListOwnedItems::Read() +{ + _worldPacket >> Auctioneer; + _worldPacket >> Offset; + + if (_worldPacket.ReadBit()) + TaintedBy.emplace(); + + Sorts.resize(_worldPacket.ReadBits(2)); + + for (AuctionSortDef& sortDef : Sorts) + _worldPacket >> sortDef; + + if (TaintedBy) + _worldPacket >> *TaintedBy; +} + void AuctionPlaceBid::Read() { _worldPacket >> Auctioneer; @@ -317,6 +474,24 @@ void AuctionReplicateItems::Read() } } +void AuctionSellCommodity::Read() +{ + _worldPacket >> Auctioneer; + _worldPacket >> UnitPrice; + _worldPacket >> RunTime; + + if (_worldPacket.ReadBit()) + TaintedBy.emplace(); + + Items.resize(_worldPacket.ReadBits(6)); + + if (TaintedBy) + _worldPacket >> *TaintedBy; + + for (AuctionItemForSale& item : Items) + _worldPacket >> item; +} + void AuctionSellItem::Read() { _worldPacket >> Auctioneer; @@ -336,6 +511,24 @@ void AuctionSellItem::Read() _worldPacket >> item; } +void AuctionSetFavoriteItem::Read() +{ + IsNotFavorite = _worldPacket.ReadBit(); + _worldPacket >> Item; +} + +void AuctionGetCommodityQuote::Read() +{ + _worldPacket >> Auctioneer; + _worldPacket >> ItemID; + _worldPacket >> Quantity; + if (_worldPacket.ReadBit()) + { + TaintedBy.emplace(); + _worldPacket >> *TaintedBy; + } +} + WorldPacket const* AuctionClosedNotification::Write() { _worldPacket << Info; diff --git a/src/server/game/Server/Packets/AuctionHousePackets.h b/src/server/game/Server/Packets/AuctionHousePackets.h index 20888842b4e..e132ca777b5 100644 --- a/src/server/game/Server/Packets/AuctionHousePackets.h +++ b/src/server/game/Server/Packets/AuctionHousePackets.h @@ -141,6 +141,52 @@ namespace WorldPackets Item::ItemInstance Item; }; + class AuctionBrowseQuery final : public ClientPacket + { + public: + AuctionBrowseQuery(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_BROWSE_QUERY, std::move(packet)) { } + + void Read() override; + + ObjectGuid Auctioneer; + uint32 Offset = 0; + uint8 MinLevel = 1; + uint8 MaxLevel = MAX_LEVEL; + uint8 Unused1007_1 = 0; + uint8 Unused1007_2 = 0; + AuctionHouseFilterMask Filters = AuctionHouseFilterMask(0); + std::vector<uint8> KnownPets; // size checked separately in Read() + int8 MaxPetLevel = 0; + Optional<Addon::AddOnInfo> TaintedBy; + std::string Name; + Array<AuctionListFilterClass, 7> ItemClassFilters; + Array<AuctionSortDef, 2> Sorts; + }; + + class AuctionCancelCommoditiesPurchase final : public ClientPacket + { + public: + AuctionCancelCommoditiesPurchase(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_CANCEL_COMMODITIES_PURCHASE, std::move(packet)) { } + + void Read() override; + + ObjectGuid Auctioneer; + Optional<Addon::AddOnInfo> TaintedBy; + }; + + class AuctionConfirmCommoditiesPurchase final : public ClientPacket + { + public: + AuctionConfirmCommoditiesPurchase(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_CONFIRM_COMMODITIES_PURCHASE, std::move(packet)) { } + + void Read() override; + + ObjectGuid Auctioneer; + int32 ItemID = 0; + uint32 Quantity = 0; + Optional<Addon::AddOnInfo> TaintedBy; + }; + class AuctionHelloRequest final : public ClientPacket { public: @@ -151,6 +197,76 @@ namespace WorldPackets ObjectGuid Guid; }; + class AuctionListBiddedItems final : public ClientPacket + { + public: + AuctionListBiddedItems(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_LIST_BIDDED_ITEMS, std::move(packet)) { } + + void Read() override; + + ObjectGuid Auctioneer; + uint32 Offset = 0; + Array<uint32, 100> AuctionIDs; + Array<AuctionSortDef, 2> Sorts; + Optional<Addon::AddOnInfo> TaintedBy; + }; + + class AuctionListBucketsByBucketKeys final : public ClientPacket + { + public: + AuctionListBucketsByBucketKeys(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_LIST_BUCKETS_BY_BUCKET_KEYS, std::move(packet)) { } + + void Read() override; + + ObjectGuid Auctioneer; + Optional<Addon::AddOnInfo> TaintedBy; + Array<AuctionBucketKey, 100> BucketKeys; + Array<AuctionSortDef, 2> Sorts; + }; + + class AuctionListItemsByBucketKey final : public ClientPacket + { + public: + AuctionListItemsByBucketKey(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_LIST_ITEMS_BY_BUCKET_KEY, std::move(packet)) { } + + void Read() override; + + ObjectGuid Auctioneer; + uint32 Offset = 0; + int8 Unknown830 = 0; + Optional<Addon::AddOnInfo> TaintedBy; + Array<AuctionSortDef, 2> Sorts; + AuctionBucketKey BucketKey; + }; + + class AuctionListItemsByItemID final : public ClientPacket + { + public: + AuctionListItemsByItemID(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_LIST_ITEMS_BY_ITEM_ID, std::move(packet)) { } + + void Read() override; + + ObjectGuid Auctioneer; + int32 ItemID = 0; + int32 SuffixItemNameDescriptionID = 0; + uint32 Offset = 0; + Optional<Addon::AddOnInfo> TaintedBy; + Array<AuctionSortDef, 2> Sorts; + }; + + class AuctionListOwnedItems final : public ClientPacket + { + public: + AuctionListOwnedItems(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_LIST_OWNED_ITEMS, std::move(packet)) { } + + void Read() override; + + ObjectGuid Auctioneer; + uint32 Offset = 0; + Optional<Addon::AddOnInfo> TaintedBy; + Array<AuctionSortDef, 2> Sorts; + }; + class AuctionPlaceBid final : public ClientPacket { public: @@ -192,6 +308,20 @@ namespace WorldPackets Optional<Addon::AddOnInfo> TaintedBy; }; + class AuctionSellCommodity final : public ClientPacket + { + public: + AuctionSellCommodity(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_SELL_COMMODITY, std::move(packet)) { } + + void Read() override; + + ObjectGuid Auctioneer; + uint64 UnitPrice = 0; + uint32 RunTime = 0; + Optional<Addon::AddOnInfo> TaintedBy; + Array<AuctionItemForSale, 64> Items; + }; + class AuctionSellItem final : public ClientPacket { public: @@ -207,6 +337,30 @@ namespace WorldPackets Array<AuctionItemForSale, 1> Items; }; + class AuctionSetFavoriteItem final : public ClientPacket + { + public: + AuctionSetFavoriteItem(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_SET_FAVORITE_ITEM, std::move(packet)) { } + + void Read() override; + + AuctionFavoriteInfo Item; + bool IsNotFavorite = true; + }; + + class AuctionGetCommodityQuote final : public ClientPacket + { + public: + AuctionGetCommodityQuote(WorldPacket&& packet) : ClientPacket(CMSG_AUCTION_GET_COMMODITY_QUOTE, std::move(packet)) { } + + void Read() override; + + ObjectGuid Auctioneer; + int32 ItemID = 0; + uint32 Quantity = 0; + Optional<Addon::AddOnInfo> TaintedBy; + }; + class AuctionClosedNotification final : public ServerPacket { public: diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 7e04f22050f..960ca2487ee 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -170,11 +170,22 @@ void OpcodeTable::InitializeClientOpcodes() DEFINE_HANDLER(CMSG_ATTACK_SWING, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleAttackSwingOpcode); DEFINE_HANDLER(CMSG_AUCTIONABLE_TOKEN_SELL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_AUCTIONABLE_TOKEN_SELL_AT_MARKET_PRICE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_AUCTION_BROWSE_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionBrowseQuery); + DEFINE_HANDLER(CMSG_AUCTION_CANCEL_COMMODITIES_PURCHASE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionCancelCommoditiesPurchase); + DEFINE_HANDLER(CMSG_AUCTION_CONFIRM_COMMODITIES_PURCHASE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionConfirmCommoditiesPurchase); + DEFINE_HANDLER(CMSG_AUCTION_GET_COMMODITY_QUOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionGetCommodityQuote); DEFINE_HANDLER(CMSG_AUCTION_HELLO_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionHelloOpcode); + DEFINE_HANDLER(CMSG_AUCTION_LIST_BIDDED_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListBiddedItems); + DEFINE_HANDLER(CMSG_AUCTION_LIST_BUCKETS_BY_BUCKET_KEYS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListBucketsByBucketKeys); + DEFINE_HANDLER(CMSG_AUCTION_LIST_ITEMS_BY_BUCKET_KEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListItemsByBucketKey); + DEFINE_HANDLER(CMSG_AUCTION_LIST_ITEMS_BY_ITEM_ID, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListItemsByItemID); + DEFINE_HANDLER(CMSG_AUCTION_LIST_OWNED_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListOwnedItems); DEFINE_HANDLER(CMSG_AUCTION_PLACE_BID, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionPlaceBid); DEFINE_HANDLER(CMSG_AUCTION_REMOVE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionRemoveItem); DEFINE_HANDLER(CMSG_AUCTION_REPLICATE_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionReplicateItems); + DEFINE_HANDLER(CMSG_AUCTION_SELL_COMMODITY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionSellCommodity); DEFINE_HANDLER(CMSG_AUCTION_SELL_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionSellItem); + DEFINE_HANDLER(CMSG_AUCTION_SET_FAVORITE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionSetFavoriteItem); DEFINE_HANDLER(CMSG_AUTH_CONTINUED_SESSION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_EarlyProccess); DEFINE_HANDLER(CMSG_AUTH_SESSION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_EarlyProccess); DEFINE_HANDLER(CMSG_AUTOBANK_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleAutoBankItemOpcode); diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index 2b7c6bc6a7b..a7de82b53a1 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -68,15 +68,26 @@ enum OpcodeClient : uint32 CMSG_ATTACK_SWING = 0x34010B, CMSG_AUCTIONABLE_TOKEN_SELL = 0x39011B, CMSG_AUCTIONABLE_TOKEN_SELL_AT_MARKET_PRICE = 0x39011C, + CMSG_AUCTION_BROWSE_QUERY = 0x35005C, + CMSG_AUCTION_CANCEL_COMMODITIES_PURCHASE = 0x350064, + CMSG_AUCTION_CONFIRM_COMMODITIES_PURCHASE = 0x350063, + CMSG_AUCTION_GET_COMMODITY_QUOTE = 0x350062, CMSG_AUCTION_HELLO_REQUEST = 0x350054, + CMSG_AUCTION_LIST_BIDDED_ITEMS = 0x350060, CMSG_AUCTION_LIST_BIDDER_ITEMS = 0x35005A, + CMSG_AUCTION_LIST_BUCKETS_BY_BUCKET_KEYS = 0x350061, CMSG_AUCTION_LIST_ITEMS = 0x350057, + CMSG_AUCTION_LIST_ITEMS_BY_BUCKET_KEY = 0x35005D, + CMSG_AUCTION_LIST_ITEMS_BY_ITEM_ID = 0x35005E, + CMSG_AUCTION_LIST_OWNED_ITEMS = 0x35005F, CMSG_AUCTION_LIST_OWNER_ITEMS = 0x350059, CMSG_AUCTION_LIST_PENDING_SALES = 0x350066, CMSG_AUCTION_PLACE_BID = 0x35005B, CMSG_AUCTION_REMOVE_ITEM = 0x350056, CMSG_AUCTION_REPLICATE_ITEMS = 0x350058, + CMSG_AUCTION_SELL_COMMODITY = 0x350065, CMSG_AUCTION_SELL_ITEM = 0x350055, + CMSG_AUCTION_SET_FAVORITE_ITEM = 0x39016A, CMSG_AUTH_CONTINUED_SESSION = 0x3A0002, CMSG_AUTH_SESSION = 0x3A0001, CMSG_AUTOBANK_ITEM = 0x360003, @@ -800,22 +811,22 @@ enum OpcodeServer : uint32 SMSG_ATTACK_SWING_ERROR = 0x41002A, SMSG_ATTACK_SWING_LANDED_LOG = 0x41002B, SMSG_AUCTIONABLE_TOKEN_AUCTION_SOLD = 0x3B0271, - SMSG_AUCTIONABLE_TOKEN_SELL_AT_MARKET_PRICE_RESPONSE = 0x3B0270, + SMSG_AUCTIONABLE_TOKEN_SELL_AT_MARKET_PRICE_RESPONSE = 0x3B0270, SMSG_AUCTIONABLE_TOKEN_SELL_CONFIRM_REQUIRED = 0x3B026F, + SMSG_AUCTION_FAVORITE_LIST = 0x3B02F2, SMSG_AUCTION_CLOSED_NOTIFICATION = 0x3B018F, SMSG_AUCTION_COMMAND_RESULT = 0x3B018C, + SMSG_AUCTION_DISABLE_NEW_POSTINGS = 0x3B0322, + SMSG_AUCTION_GET_COMMODITY_QUOTE_RESULT = 0x3B02EA, SMSG_AUCTION_HELLO_RESPONSE = 0x3B018A, + SMSG_AUCTION_LIST_BIDDED_ITEMS_RESULT = 0x3B02E9, + SMSG_AUCTION_LIST_BUCKETS_RESULT = 0x3B02E5, SMSG_AUCTION_LIST_ITEMS_RESULT = 0x3B02E6, + SMSG_AUCTION_LIST_OWNED_ITEMS_RESULT = 0x3B02E8, SMSG_AUCTION_OUTBID_NOTIFICATION = 0x3B018E, SMSG_AUCTION_OWNER_BID_NOTIFICATION = 0x3B0190, SMSG_AUCTION_REPLICATE_RESPONSE = 0x3B018B, SMSG_AUCTION_WON_NOTIFICATION = 0x3B018D, - SMSG_AUCTION_DISABLE_NEW_POSTINGS = 0x3B0322, - SMSG_AUCTION_FAVORITE_LIST = 0x3B02F2, - SMSG_AUCTION_GET_COMMODITY_QUOTE_RESULT = 0x3B02EA, - SMSG_AUCTION_LIST_BIDDED_ITEMS_RESULT = 0x3B02E9, - SMSG_AUCTION_LIST_BUCKETS_RESULT = 0x3B02E5, - SMSG_AUCTION_LIST_OWNED_ITEMS_RESULT = 0x3B02E8, SMSG_AURA_POINTS_DEPLETED = 0x510012, SMSG_AURA_UPDATE = 0x510011, SMSG_AUTH_CHALLENGE = 0x420000, diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 7a3ef59d131..9f2815750eb 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -119,11 +119,23 @@ namespace WorldPackets namespace AuctionHouse { + class AuctionBrowseQuery; + class AuctionCancelCommoditiesPurchase; + class AuctionConfirmCommoditiesPurchase; + class AuctionGetCommodityQuote; class AuctionHelloRequest; + class AuctionListBiddedItems; + class AuctionListBucketsByBucketKeys; + class AuctionListItemsByBucketKey; + class AuctionListItemsByItemID; + class AuctionListOwnedItems; class AuctionPlaceBid; class AuctionRemoveItem; class AuctionReplicateItems; + class AuctionRequestFavoriteList; + class AuctionSellCommodity; class AuctionSellItem; + class AuctionSetFavoriteItem; } namespace Auth @@ -1359,11 +1371,23 @@ class TC_GAME_API WorldSession void HandleSetTradeItemOpcode(WorldPackets::Trade::SetTradeItem& setTradeItem); void HandleUnacceptTradeOpcode(WorldPackets::Trade::UnacceptTrade& unacceptTrade); + void HandleAuctionBrowseQuery(WorldPackets::AuctionHouse::AuctionBrowseQuery& browseQuery); + void HandleAuctionCancelCommoditiesPurchase(WorldPackets::AuctionHouse::AuctionCancelCommoditiesPurchase& cancelCommoditiesPurchase); + void HandleAuctionConfirmCommoditiesPurchase(WorldPackets::AuctionHouse::AuctionConfirmCommoditiesPurchase& confirmCommoditiesPurchase); + void HandleAuctionGetCommodityQuote(WorldPackets::AuctionHouse::AuctionGetCommodityQuote& startCommoditiesPurchase); void HandleAuctionHelloOpcode(WorldPackets::AuctionHouse::AuctionHelloRequest& hello); + void HandleAuctionListBiddedItems(WorldPackets::AuctionHouse::AuctionListBiddedItems& listBiddedItems); + void HandleAuctionListBucketsByBucketKeys(WorldPackets::AuctionHouse::AuctionListBucketsByBucketKeys& listBucketsByBucketKeys); + void HandleAuctionListItemsByBucketKey(WorldPackets::AuctionHouse::AuctionListItemsByBucketKey& listItemsByBucketKey); + void HandleAuctionListItemsByItemID(WorldPackets::AuctionHouse::AuctionListItemsByItemID& listItemsByItemID); + void HandleAuctionListOwnedItems(WorldPackets::AuctionHouse::AuctionListOwnedItems& listOwnedItems); void HandleAuctionPlaceBid(WorldPackets::AuctionHouse::AuctionPlaceBid& placeBid); void HandleAuctionRemoveItem(WorldPackets::AuctionHouse::AuctionRemoveItem& removeItem); void HandleAuctionReplicateItems(WorldPackets::AuctionHouse::AuctionReplicateItems& replicateItems); + void SendAuctionFavoriteList(); + void HandleAuctionSellCommodity(WorldPackets::AuctionHouse::AuctionSellCommodity& sellCommodity); void HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSellItem& sellItem); + void HandleAuctionSetFavoriteItem(WorldPackets::AuctionHouse::AuctionSetFavoriteItem& setFavoriteItem); // Bank void HandleAutoBankItemOpcode(WorldPackets::Bank::AutoBankItem& packet); |