feat(Core/AuctionHouse): Rework auctionhouse search threading (#20830)
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "AuctionHouseMgr.h"
|
||||
#include "AuctionHouseSearcher.h"
|
||||
#include "Common.h"
|
||||
#include "DBCStores.h"
|
||||
#include "DatabaseEnv.h"
|
||||
@@ -32,194 +33,18 @@
|
||||
|
||||
constexpr auto AH_MINIMUM_DEPOSIT = 100;
|
||||
|
||||
// Proof of concept, we should shift the info we're obtaining in here into AuctionEntry probably
|
||||
static bool SortAuction(AuctionEntry* left, AuctionEntry* right, AuctionSortOrderVector& sortOrder, Player* player, bool checkMinBidBuyout)
|
||||
{
|
||||
for (auto& thisOrder : sortOrder)
|
||||
{
|
||||
switch (thisOrder.sortOrder)
|
||||
{
|
||||
case AUCTION_SORT_BID:
|
||||
{
|
||||
if (left->bid == right->bid)
|
||||
{
|
||||
if (checkMinBidBuyout)
|
||||
{
|
||||
if (left->buyout == right->buyout)
|
||||
{
|
||||
if (left->startbid == right->startbid)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? left->startbid > right->startbid : left->startbid < right->startbid;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? left->buyout > right->buyout : left->buyout < right->buyout;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? left->bid > right->bid : left->bid < right->bid;
|
||||
}
|
||||
case AUCTION_SORT_BUYOUT:
|
||||
case AUCTION_SORT_BUYOUT_2:
|
||||
{
|
||||
if (left->buyout == right->buyout)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? left->buyout > right->buyout : left->buyout < right->buyout;
|
||||
}
|
||||
case AUCTION_SORT_ITEM:
|
||||
{
|
||||
ItemTemplate const* protoLeft = sObjectMgr->GetItemTemplate(left->item_template);
|
||||
ItemTemplate const* protoRight = sObjectMgr->GetItemTemplate(right->item_template);
|
||||
if (!protoLeft || !protoRight)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string leftName = protoLeft->Name1;
|
||||
std::string rightName = protoRight->Name1;
|
||||
if (leftName.empty() || rightName.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LocaleConstant locale = LOCALE_enUS;
|
||||
if (player && player->GetSession())
|
||||
{
|
||||
locale = player->GetSession()->GetSessionDbLocaleIndex();
|
||||
}
|
||||
|
||||
if (locale > LOCALE_enUS)
|
||||
{
|
||||
if (ItemLocale const* leftIl = sObjectMgr->GetItemLocale(protoLeft->ItemId))
|
||||
{
|
||||
ObjectMgr::GetLocaleString(leftIl->Name, locale, leftName);
|
||||
}
|
||||
|
||||
if (ItemLocale const* rightIl = sObjectMgr->GetItemLocale(protoRight->ItemId))
|
||||
{
|
||||
ObjectMgr::GetLocaleString(rightIl->Name, locale, rightName);
|
||||
}
|
||||
}
|
||||
|
||||
int result = leftName.compare(rightName);
|
||||
if (result == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? result > 0 : result < 0;
|
||||
}
|
||||
case AUCTION_SORT_MINLEVEL:
|
||||
{
|
||||
ItemTemplate const* protoLeft = sObjectMgr->GetItemTemplate(left->item_template);
|
||||
ItemTemplate const* protoRight = sObjectMgr->GetItemTemplate(right->item_template);
|
||||
if (!protoLeft || !protoRight)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (protoLeft->RequiredLevel == protoRight->RequiredLevel)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? protoLeft->RequiredLevel > protoRight->RequiredLevel : protoLeft->RequiredLevel < protoRight->RequiredLevel;
|
||||
}
|
||||
case AUCTION_SORT_OWNER:
|
||||
{
|
||||
std::string leftName;
|
||||
sCharacterCache->GetCharacterNameByGuid(left->owner, leftName);
|
||||
|
||||
std::string rightName;
|
||||
sCharacterCache->GetCharacterNameByGuid(right->owner, rightName);
|
||||
|
||||
int result = leftName.compare(rightName);
|
||||
if (result == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? result > 0 : result < 0;
|
||||
}
|
||||
case AUCTION_SORT_RARITY:
|
||||
{
|
||||
ItemTemplate const* protoLeft = sObjectMgr->GetItemTemplate(left->item_template);
|
||||
ItemTemplate const* protoRight = sObjectMgr->GetItemTemplate(right->item_template);
|
||||
if (!protoLeft || !protoRight)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (protoLeft->Quality == protoRight->Quality)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? protoLeft->Quality > protoRight->Quality : protoLeft->Quality < protoRight->Quality;
|
||||
}
|
||||
case AUCTION_SORT_STACK:
|
||||
{
|
||||
if (left->itemCount == right->itemCount)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!thisOrder.isDesc)
|
||||
{
|
||||
return (left->itemCount < right->itemCount);
|
||||
}
|
||||
|
||||
return (left->itemCount > right->itemCount);
|
||||
}
|
||||
case AUCTION_SORT_TIMELEFT:
|
||||
{
|
||||
if (left->expire_time == right->expire_time)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? left->expire_time > right->expire_time : left->expire_time < right->expire_time;
|
||||
}
|
||||
case AUCTION_SORT_MINBIDBUY:
|
||||
{
|
||||
if (left->buyout == right->buyout)
|
||||
{
|
||||
if (left->startbid == right->startbid)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? left->startbid > right->startbid : left->startbid < right->startbid;
|
||||
}
|
||||
|
||||
return thisOrder.isDesc ? left->buyout > right->buyout : left->buyout < right->buyout;
|
||||
}
|
||||
case AUCTION_SORT_MAX:
|
||||
// Such sad travis appeasement
|
||||
case AUCTION_SORT_UNK4:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AuctionHouseMgr::AuctionHouseMgr()
|
||||
AuctionHouseMgr::AuctionHouseMgr() : _auctionHouseSearcher(new AuctionHouseSearcher())
|
||||
{
|
||||
_updateIntervalTimer.SetInterval(MINUTE * IN_MILLISECONDS);
|
||||
_updateIntervalTimer.SetCurrent(MINUTE * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
AuctionHouseMgr::~AuctionHouseMgr()
|
||||
{
|
||||
for (ItemMap::iterator itr = _mAitems.begin(); itr != _mAitems.end(); ++itr)
|
||||
delete itr->second;
|
||||
|
||||
delete _auctionHouseSearcher;
|
||||
}
|
||||
|
||||
AuctionHouseMgr* AuctionHouseMgr::instance()
|
||||
@@ -245,17 +70,19 @@ AuctionHouseObject* AuctionHouseMgr::GetAuctionsMap(uint32 factionTemplateId)
|
||||
return &_neutralAuctions;
|
||||
}
|
||||
|
||||
AuctionHouseObject* AuctionHouseMgr::GetAuctionsMapByHouseId(uint8 auctionHouseId)
|
||||
AuctionHouseObject* AuctionHouseMgr::GetAuctionsMapByHouseId(AuctionHouseId auctionHouseId)
|
||||
{
|
||||
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
|
||||
return &_neutralAuctions;
|
||||
|
||||
switch (auctionHouseId)
|
||||
{
|
||||
case AUCTIONHOUSE_ALLIANCE:
|
||||
case AuctionHouseId::Alliance:
|
||||
return &_allianceAuctions;
|
||||
case AUCTIONHOUSE_HORDE:
|
||||
case AuctionHouseId::Horde:
|
||||
return &_hordeAuctions;
|
||||
case AuctionHouseId::Neutral:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -294,13 +121,9 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, CharacterDatabas
|
||||
uint32 bidder_accId = 0;
|
||||
Player* bidder = ObjectAccessor::FindConnectedPlayer(auction->bidder);
|
||||
if (bidder)
|
||||
{
|
||||
bidder_accId = bidder->GetSession()->GetAccountId();
|
||||
}
|
||||
else
|
||||
{
|
||||
bidder_accId = sCharacterCache->GetCharacterAccountIdByGuid(auction->bidder);
|
||||
}
|
||||
|
||||
// receiver exist
|
||||
if (bidder || bidder_accId)
|
||||
@@ -316,20 +139,20 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, CharacterDatabas
|
||||
if (bidder)
|
||||
{
|
||||
if (sendNotification) // can be changed in the hook
|
||||
bidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, auction->bidder, 0, 0, auction->item_template);
|
||||
bidder->GetSession()->SendAuctionBidderNotification((uint32)auction->GetHouseId(), auction->Id, auction->bidder, 0, 0, auction->item_template);
|
||||
|
||||
if (updateAchievementCriteria) // can be changed in the hook
|
||||
bidder->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1);
|
||||
}
|
||||
else if (updateAchievementCriteria)
|
||||
{
|
||||
sAchievementMgr->UpdateAchievementCriteriaForOfflinePlayer(auction->bidder.GetCounter(), ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1);
|
||||
}
|
||||
|
||||
if (sendMail) // can be changed in the hook
|
||||
{
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_WON), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout))
|
||||
.AddItem(pItem)
|
||||
.SendMailTo(trans, MailReceiver(bidder, auction->bidder.GetCounter()), auction, MAIL_CHECK_MASK_COPIED);
|
||||
.AddItem(pItem)
|
||||
.SendMailTo(trans, MailReceiver(bidder, auction->bidder.GetCounter()), auction, MAIL_CHECK_MASK_COPIED);
|
||||
}
|
||||
}
|
||||
else
|
||||
sAuctionMgr->RemoveAItem(auction->item_guid, true, &trans);
|
||||
@@ -426,9 +249,11 @@ void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry* auction, CharacterDat
|
||||
owner->GetSession()->SendAuctionOwnerNotification(auction);
|
||||
|
||||
if (sendMail) // can be changed in the hook
|
||||
{
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_EXPIRED), AuctionEntry::BuildAuctionMailBody(ObjectGuid::Empty, 0, auction->buyout, auction->deposit))
|
||||
.AddItem(pItem)
|
||||
.SendMailTo(trans, MailReceiver(owner, auction->owner.GetCounter()), auction, MAIL_CHECK_MASK_COPIED, 0);
|
||||
.AddItem(pItem)
|
||||
.SendMailTo(trans, MailReceiver(owner, auction->owner.GetCounter()), auction, MAIL_CHECK_MASK_COPIED, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
sAuctionMgr->RemoveAItem(auction->item_guid, true, &trans);
|
||||
@@ -449,7 +274,7 @@ void AuctionHouseMgr::SendAuctionOutbiddedMail(AuctionEntry* auction, uint32 new
|
||||
sScriptMgr->OnBeforeAuctionHouseMgrSendAuctionOutbiddedMail(this, auction, oldBidder, oldBidder_accId, newBidder, newPrice, sendNotification, sendMail);
|
||||
|
||||
if (oldBidder && newBidder && sendNotification) // can be changed in the hook
|
||||
oldBidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, newBidder->GetGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template);
|
||||
oldBidder->GetSession()->SendAuctionBidderNotification((uint32)auction->GetHouseId(), auction->Id, newBidder->GetGUID(), newPrice, AuctionEntry::CalculateAuctionOutBid(auction->bid), auction->item_template);
|
||||
|
||||
if (sendMail) // can be changed in the hook
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_OUTBIDDED), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut()))
|
||||
@@ -564,7 +389,7 @@ void AuctionHouseMgr::LoadAuctions()
|
||||
continue;
|
||||
}
|
||||
|
||||
GetAuctionsMapByHouseId(aItem->houseId)->AddAuction(aItem);
|
||||
GetAuctionsMapByHouseId(AuctionHouseId(aItem->houseId))->AddAuction(aItem);
|
||||
count++;
|
||||
} while (result->NextRow());
|
||||
|
||||
@@ -598,40 +423,57 @@ bool AuctionHouseMgr::RemoveAItem(ObjectGuid itemGuid, bool deleteFromDB, Charac
|
||||
return true;
|
||||
}
|
||||
|
||||
void AuctionHouseMgr::Update()
|
||||
void AuctionHouseMgr::Update(uint32 const diff)
|
||||
{
|
||||
sScriptMgr->OnBeforeAuctionHouseMgrUpdate();
|
||||
_hordeAuctions.Update();
|
||||
_allianceAuctions.Update();
|
||||
_neutralAuctions.Update();
|
||||
}
|
||||
|
||||
AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntry(uint32 factionTemplateId)
|
||||
{
|
||||
uint32 houseid = AUCTIONHOUSE_NEUTRAL; // goblin auction house
|
||||
|
||||
if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
|
||||
_updateIntervalTimer.Update(diff);
|
||||
if (_updateIntervalTimer.Passed())
|
||||
{
|
||||
//FIXME: found way for proper auctionhouse selection by another way
|
||||
// AuctionHouse.dbc have faction field with _player_ factions associated with auction house races.
|
||||
// but no easy way convert creature faction to player race faction for specific city
|
||||
FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId);
|
||||
if (!u_entry)
|
||||
houseid = AUCTIONHOUSE_NEUTRAL; // goblin auction house
|
||||
else if (u_entry->ourMask & FACTION_MASK_ALLIANCE)
|
||||
houseid = AUCTIONHOUSE_ALLIANCE; // human auction house
|
||||
else if (u_entry->ourMask & FACTION_MASK_HORDE)
|
||||
houseid = AUCTIONHOUSE_HORDE; // orc auction house
|
||||
else
|
||||
houseid = AUCTIONHOUSE_NEUTRAL; // goblin auction house
|
||||
sScriptMgr->OnBeforeAuctionHouseMgrUpdate();
|
||||
|
||||
_hordeAuctions.Update();
|
||||
_allianceAuctions.Update();
|
||||
_neutralAuctions.Update();
|
||||
|
||||
_updateIntervalTimer.Reset();
|
||||
}
|
||||
|
||||
return sAuctionHouseStore.LookupEntry(houseid);
|
||||
_auctionHouseSearcher->Update();
|
||||
}
|
||||
|
||||
AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntryFromHouse(uint8 houseId)
|
||||
AuctionHouseFaction AuctionHouseMgr::GetAuctionHouseFactionFromHouseId(AuctionHouseId ahHouseId)
|
||||
{
|
||||
return (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) ? sAuctionHouseStore.LookupEntry(AUCTIONHOUSE_NEUTRAL) : sAuctionHouseStore.LookupEntry(houseId);
|
||||
switch (ahHouseId)
|
||||
{
|
||||
case AuctionHouseId::Alliance:
|
||||
return AuctionHouseFaction::Alliance;
|
||||
case AuctionHouseId::Horde:
|
||||
return AuctionHouseFaction::Horde;
|
||||
case AuctionHouseId::Neutral:
|
||||
return AuctionHouseFaction::Neutral;
|
||||
}
|
||||
return AuctionHouseFaction::Neutral;
|
||||
}
|
||||
|
||||
AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntryFromFactionTemplate(uint32 factionTemplateId)
|
||||
{
|
||||
AuctionHouseId houseid;
|
||||
FactionTemplateEntry const* uEntry = sFactionTemplateStore.LookupEntry(factionTemplateId);
|
||||
|
||||
if (!uEntry || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
|
||||
houseid = AuctionHouseId::Neutral;
|
||||
else if (uEntry->ourMask & FACTION_MASK_ALLIANCE)
|
||||
houseid = AuctionHouseId::Alliance;
|
||||
else if (uEntry->ourMask & FACTION_MASK_HORDE)
|
||||
houseid = AuctionHouseId::Horde;
|
||||
else
|
||||
houseid = AuctionHouseId::Neutral;
|
||||
|
||||
return sAuctionHouseStore.LookupEntry((uint32)houseid);
|
||||
}
|
||||
|
||||
AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntryFromHouse(AuctionHouseId ahHouseId)
|
||||
{
|
||||
return (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) ? sAuctionHouseStore.LookupEntry((uint32)AuctionHouseId::Neutral) : sAuctionHouseStore.LookupEntry((uint32)ahHouseId);
|
||||
}
|
||||
|
||||
void AuctionHouseObject::AddAuction(AuctionEntry* auction)
|
||||
@@ -639,12 +481,15 @@ void AuctionHouseObject::AddAuction(AuctionEntry* auction)
|
||||
ASSERT(auction);
|
||||
|
||||
_auctionsMap[auction->Id] = auction;
|
||||
sAuctionMgr->GetAuctionHouseSearcher()->AddAuction(auction);
|
||||
|
||||
sScriptMgr->OnAuctionAdd(this, auction);
|
||||
}
|
||||
|
||||
bool AuctionHouseObject::RemoveAuction(AuctionEntry* auction)
|
||||
{
|
||||
bool wasInMap = !!_auctionsMap.erase(auction->Id);
|
||||
sAuctionMgr->GetAuctionHouseSearcher()->RemoveAuction(auction);
|
||||
|
||||
sScriptMgr->OnAuctionRemove(this, auction);
|
||||
|
||||
@@ -700,273 +545,9 @@ void AuctionHouseObject::Update()
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void AuctionHouseObject::BuildListBidderItems(WorldPacket& data, Player* player, uint32& count, uint32& totalcount)
|
||||
AuctionHouseFaction AuctionEntry::GetFactionId() const
|
||||
{
|
||||
for (AuctionEntryMap::const_iterator itr = _auctionsMap.begin(); itr != _auctionsMap.end(); ++itr)
|
||||
{
|
||||
AuctionEntry* Aentry = itr->second;
|
||||
if (Aentry && Aentry->bidder == player->GetGUID())
|
||||
{
|
||||
if (itr->second->BuildAuctionInfo(data))
|
||||
++count;
|
||||
|
||||
++totalcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AuctionHouseObject::BuildListOwnerItems(WorldPacket& data, Player* player, uint32& count, uint32& totalcount)
|
||||
{
|
||||
for (AuctionEntryMap::const_iterator itr = _auctionsMap.begin(); itr != _auctionsMap.end(); ++itr)
|
||||
{
|
||||
AuctionEntry* Aentry = itr->second;
|
||||
if (Aentry && Aentry->owner == player->GetGUID())
|
||||
{
|
||||
if (Aentry->BuildAuctionInfo(data))
|
||||
++count;
|
||||
|
||||
++totalcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player,
|
||||
std::wstring const& wsearchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable,
|
||||
uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality,
|
||||
uint32& count, uint32& totalcount, uint8 /*getAll*/, AuctionSortOrderVector const& sortOrder, Milliseconds searchTimeout)
|
||||
{
|
||||
uint32 itrcounter = 0;
|
||||
|
||||
// Ensures that listfrom is not greater that auctions count
|
||||
listfrom = std::min(listfrom, static_cast<uint32>(GetAuctions().size()));
|
||||
|
||||
std::vector<AuctionEntry*> auctionShortlist;
|
||||
|
||||
// pussywizard: optimization, this is a simplified case
|
||||
if (itemClass == 0xffffffff && itemSubClass == 0xffffffff && inventoryType == 0xffffffff && quality == 0xffffffff && levelmin == 0x00 && levelmax == 0x00 && usable == 0x00 && wsearchedname.empty())
|
||||
{
|
||||
auto itr = GetAuctionsBegin();
|
||||
for (; itr != GetAuctionsEnd(); ++itr)
|
||||
{
|
||||
auctionShortlist.push_back(itr->second);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto curTime = GameTime::GetGameTime();
|
||||
|
||||
int loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
|
||||
int locdbc_idx = player->GetSession()->GetSessionDbcLocale();
|
||||
|
||||
for (AuctionEntryMap::const_iterator itr = _auctionsMap.begin(); itr != _auctionsMap.end(); ++itr)
|
||||
{
|
||||
if ((itrcounter++) % 100 == 0) // check condition every 100 iterations
|
||||
{
|
||||
if (GetMSTimeDiff(GameTime::GetGameTimeMS(), GetTimeMS()) >= searchTimeout) // pussywizard: stop immediately if diff is high or waiting too long
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AuctionEntry* Aentry = itr->second;
|
||||
if (!Aentry)
|
||||
return false;
|
||||
|
||||
// Skip expired auctions
|
||||
if (Aentry->expire_time < curTime.count())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Item* item = sAuctionMgr->GetAItem(Aentry->item_guid);
|
||||
if (!item)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemTemplate const* proto = item->GetTemplate();
|
||||
if (itemClass != 0xffffffff && proto->Class != itemClass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (itemSubClass != 0xffffffff && proto->SubClass != itemSubClass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inventoryType != 0xffffffff && proto->InventoryType != inventoryType)
|
||||
{
|
||||
// xinef: exception, robes are counted as chests
|
||||
if (inventoryType != INVTYPE_CHEST || proto->InventoryType != INVTYPE_ROBE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (quality != 0xffffffff && proto->Quality < quality)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (usable != 0x00)
|
||||
{
|
||||
if (player->CanUseItem(item) != EQUIP_ERR_OK)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// xinef: check already learded recipes and pets
|
||||
if (proto->Spells[1].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID && player->HasSpell(proto->Spells[1].SpellId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow search by suffix (ie: of the Monkey) or partial name (ie: Monkey)
|
||||
// No need to do any of this if no search term was entered
|
||||
if (!wsearchedname.empty())
|
||||
{
|
||||
std::string name = proto->Name1;
|
||||
if (name.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// local name
|
||||
if (loc_idx >= 0)
|
||||
if (ItemLocale const* il = sObjectMgr->GetItemLocale(proto->ItemId))
|
||||
ObjectMgr::GetLocaleString(il->Name, loc_idx, name);
|
||||
|
||||
// DO NOT use GetItemEnchantMod(proto->RandomProperty) as it may return a result
|
||||
// that matches the search but it may not equal item->GetItemRandomPropertyId()
|
||||
// used in BuildAuctionInfo() which then causes wrong items to be listed
|
||||
int32 propRefID = item->GetItemRandomPropertyId();
|
||||
|
||||
if (propRefID)
|
||||
{
|
||||
// Append the suffix to the name (ie: of the Monkey) if one exists
|
||||
// These are found in ItemRandomSuffix.dbc and ItemRandomProperties.dbc
|
||||
// even though the DBC name seems misleading
|
||||
std::array<char const*, 16> const* suffix = nullptr;
|
||||
|
||||
if (propRefID < 0)
|
||||
{
|
||||
ItemRandomSuffixEntry const* itemRandEntry = sItemRandomSuffixStore.LookupEntry(-item->GetItemRandomPropertyId());
|
||||
if (itemRandEntry)
|
||||
suffix = &itemRandEntry->Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemRandomPropertiesEntry const* itemRandEntry = sItemRandomPropertiesStore.LookupEntry(item->GetItemRandomPropertyId());
|
||||
if (itemRandEntry)
|
||||
suffix = &itemRandEntry->Name;
|
||||
}
|
||||
|
||||
// dbc local name
|
||||
if (suffix)
|
||||
{
|
||||
// Append the suffix (ie: of the Monkey) to the name using localization
|
||||
// or default enUS if localization is invalid
|
||||
name += ' ';
|
||||
name += (*suffix)[locdbc_idx >= 0 ? locdbc_idx : LOCALE_enUS];
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the search (with or without suffix)
|
||||
if (!Utf8FitTo(name, wsearchedname))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auctionShortlist.push_back(Aentry);
|
||||
}
|
||||
}
|
||||
|
||||
if (auctionShortlist.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if sort enabled, and first sort column is valid, if not don't sort
|
||||
if (!sortOrder.empty())
|
||||
{
|
||||
AuctionSortInfo const& sortInfo = *sortOrder.begin();
|
||||
if (sortInfo.sortOrder >= AUCTION_SORT_MINLEVEL && sortInfo.sortOrder < AUCTION_SORT_MAX && sortInfo.sortOrder != AUCTION_SORT_UNK4)
|
||||
{
|
||||
// Partial sort to improve performance a bit, but the last pages will burn
|
||||
if (listfrom + 50 <= auctionShortlist.size())
|
||||
{
|
||||
std::partial_sort(auctionShortlist.begin(), auctionShortlist.begin() + listfrom + 50, auctionShortlist.end(),
|
||||
std::bind(SortAuction, std::placeholders::_1, std::placeholders::_2, sortOrder, player, sortInfo.sortOrder == AUCTION_SORT_BID));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::sort(auctionShortlist.begin(), auctionShortlist.end(), std::bind(SortAuction, std::placeholders::_1, std::placeholders::_2, sortOrder,
|
||||
player, sortInfo.sortOrder == AUCTION_SORT_BID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& auction : auctionShortlist)
|
||||
{
|
||||
// Add the item if no search term or if entered search term was found
|
||||
if (count < 50 && totalcount >= listfrom)
|
||||
{
|
||||
Item* item = sAuctionMgr->GetAItem(auction->item_guid);
|
||||
if (!item)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
++count;
|
||||
auction->BuildAuctionInfo(data);
|
||||
}
|
||||
++totalcount;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//this function inserts to WorldPacket auction's data
|
||||
bool AuctionEntry::BuildAuctionInfo(WorldPacket& data) const
|
||||
{
|
||||
Item* item = sAuctionMgr->GetAItem(item_guid);
|
||||
if (!item)
|
||||
{
|
||||
LOG_ERROR("auctionHouse", "AuctionEntry::BuildAuctionInfo: Auction {} has a non-existent item: {}", Id, item_guid.ToString());
|
||||
return false;
|
||||
}
|
||||
data << uint32(Id);
|
||||
data << uint32(item->GetEntry());
|
||||
|
||||
for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i)
|
||||
{
|
||||
data << uint32(item->GetEnchantmentId(EnchantmentSlot(i)));
|
||||
data << uint32(item->GetEnchantmentDuration(EnchantmentSlot(i)));
|
||||
data << uint32(item->GetEnchantmentCharges(EnchantmentSlot(i)));
|
||||
}
|
||||
|
||||
data << int32(item->GetItemRandomPropertyId()); // Random item property id
|
||||
data << uint32(item->GetItemSuffixFactor()); // SuffixFactor
|
||||
data << uint32(item->GetCount()); // item->count
|
||||
data << uint32(item->GetSpellCharges()); // item->charge FFFFFFF
|
||||
data << uint32(0); // Unknown
|
||||
data << owner; // Auction->owner
|
||||
data << uint32(startbid); // Auction->startbid (not sure if useful)
|
||||
data << uint32(bid ? GetAuctionOutBid() : 0);
|
||||
// Minimal outbid
|
||||
data << uint32(buyout); // Auction->buyout
|
||||
data << uint32((expire_time - GameTime::GetGameTime().count()) * IN_MILLISECONDS); // time left
|
||||
data << bidder; // auction->bidder current
|
||||
data << uint32(bid); // current bid
|
||||
return true;
|
||||
return AuctionHouseMgr::GetAuctionHouseFactionFromHouseId(houseId);
|
||||
}
|
||||
|
||||
uint32 AuctionEntry::GetAuctionCut() const
|
||||
@@ -975,8 +556,13 @@ uint32 AuctionEntry::GetAuctionCut() const
|
||||
return std::max(cut, 0);
|
||||
}
|
||||
|
||||
/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
|
||||
uint32 AuctionEntry::GetAuctionOutBid() const
|
||||
{
|
||||
return CalculateAuctionOutBid(bid);
|
||||
}
|
||||
|
||||
/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
|
||||
uint32 AuctionEntry::CalculateAuctionOutBid(uint32 bid)
|
||||
{
|
||||
uint32 outbid = CalculatePct(bid, 5);
|
||||
return outbid ? outbid : 1;
|
||||
@@ -1008,7 +594,7 @@ void AuctionEntry::SaveToDB(CharacterDatabaseTransaction trans) const
|
||||
bool AuctionEntry::LoadFromDB(Field* fields)
|
||||
{
|
||||
Id = fields[0].Get<uint32>();
|
||||
houseId = fields[1].Get<uint8>();
|
||||
houseId = AuctionHouseId(fields[1].Get<uint8>());
|
||||
item_guid = ObjectGuid::Create<HighGuid::Item>(fields[2].Get<uint32>());
|
||||
item_template = fields[3].Get<uint32>();
|
||||
itemCount = fields[4].Get<uint32>();
|
||||
|
||||
Reference in New Issue
Block a user