aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpete318 <pete318@users.noreply.github.com>2016-02-03 00:45:31 +0000
committerShauren <shauren.trinity@gmail.com>2016-04-10 17:48:29 +0200
commit7d5d79aa015b21969a1f5ca75ca3efe8cb842f25 (patch)
treee21f6f3a63c2a4a3a0891fc4348dee866200dd67
parentb23a6aeaff403266491ea75207558bf9917b9cc4 (diff)
Implement AuctionHouse features: GetAll scan and search throttling
Implements two standard features of the Auction House. * GetAll scan, retrieves all auctions and sends them in a single packet. There's a limitation on how often a player can do this (Max 55000 items) * Search throttling. For normal searches, the server can send a time in milliseconds to the client, the client will wait that long between searches. Delay set in config Closes #16469 (cherry picked from commit 3aaeb574050668e5a240078f6e40337c3975d110)
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp60
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.h25
-rw-r--r--src/server/game/Handlers/AuctionHouseHandler.cpp24
-rw-r--r--src/server/game/Server/Packets/AuctionHousePackets.cpp9
-rw-r--r--src/server/game/Server/Packets/AuctionHousePackets.h8
-rw-r--r--src/server/game/World/World.cpp7
-rw-r--r--src/server/game/World/World.h2
-rw-r--r--src/server/worldserver/worldserver.conf.dist18
8 files changed, 132 insertions, 21 deletions
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index ce8815dee07..1ea1099cd96 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -581,6 +581,15 @@ void AuctionHouseObject::Update()
if (AuctionsMap.empty())
return;
+ // Clear expired throttled players
+ for (PlayerGetAllThrottleMap::const_iterator itr = GetAllThrottleMap.begin(); itr != GetAllThrottleMap.end();)
+ {
+ if (itr->second.NextAllowedReplication <= curTime)
+ itr = GetAllThrottleMap.erase(itr);
+ else
+ ++itr;
+ }
+
SQLTransaction trans = CharacterDatabase.BeginTransaction();
for (AuctionEntryMap::iterator it = AuctionsMap.begin(); it != AuctionsMap.end();)
@@ -736,16 +745,61 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPackets::AuctionHouse::Aucti
// Add the item if no search term or if entered search term was found
if (packet.Items.size() < 50 && totalcount >= listfrom)
- Aentry->BuildAuctionInfo(packet.Items, true);
+ Aentry->BuildAuctionInfo(packet.Items, true, item);
++totalcount;
}
}
+void AuctionHouseObject::BuildReplicate(WorldPackets::AuctionHouse::AuctionReplicateResponse& auctionReplicateResult, Player* player,
+ uint32 global, uint32 cursor, uint32 tombstone, uint32 count)
+{
+ time_t curTime = sWorld->GetGameTime();
+
+ auto throttleItr = GetAllThrottleMap.find(player->GetGUID());
+ if (throttleItr != GetAllThrottleMap.end())
+ {
+ if (throttleItr->second.Global != global || throttleItr->second.Cursor != cursor || throttleItr->second.Tombstone != tombstone)
+ return;
+
+ if (!throttleItr->second.IsReplicationInProgress() && throttleItr->second.NextAllowedReplication > curTime)
+ return;
+ }
+ else
+ {
+ throttleItr = GetAllThrottleMap.insert({ player->GetGUID(), PlayerGetAllThrottleData{} }).first;
+ throttleItr->second.NextAllowedReplication = curTime + sWorld->getIntConfig(CONFIG_AUCTION_GETALL_DELAY);
+ throttleItr->second.Global = uint32(curTime);
+ }
+
+ if (AuctionsMap.empty() || !count)
+ return;
+
+ auto itr = AuctionsMap.upper_bound(cursor);
+ for (; itr != AuctionsMap.end(); ++itr)
+ {
+ AuctionEntry* auction = itr->second;
+ if (auction->expire_time < curTime)
+ continue;
+
+ Item* item = sAuctionMgr->GetAItem(auction->itemGUIDLow);
+ if (!item)
+ continue;
+
+ auction->BuildAuctionInfo(auctionReplicateResult.Items, true, item);
+ if (!--count)
+ break;
+ }
+
+ auctionReplicateResult.ChangeNumberGlobal = throttleItr->second.Global;
+ auctionReplicateResult.ChangeNumberCursor = throttleItr->second.Cursor = !auctionReplicateResult.Items.empty() ? auctionReplicateResult.Items.back().AuctionItemID : 0;
+ auctionReplicateResult.ChangeNumberTombstone = throttleItr->second.Tombstone = !count ? AuctionsMap.rbegin()->first : 0;
+}
+
//this function inserts to WorldPacket auction's data
-void AuctionEntry::BuildAuctionInfo(std::vector<WorldPackets::AuctionHouse::AuctionItem>& items, bool listAuctionItems) const
+void AuctionEntry::BuildAuctionInfo(std::vector<WorldPackets::AuctionHouse::AuctionItem>& items, bool listAuctionItems, Item* sourceItem /*= nullptr*/) const
{
- Item* item = sAuctionMgr->GetAItem(itemGUIDLow);
+ Item* item = (sourceItem) ? sourceItem : sAuctionMgr->GetAItem(itemGUIDLow);
if (!item)
{
TC_LOG_ERROR("misc", "AuctionEntry::BuildAuctionInfo: Auction %u has a non-existent item: " UI64FMTD, Id, itemGUIDLow);
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h
index ae9a6c1e894..17b72a24c22 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.h
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h
@@ -87,7 +87,7 @@ struct TC_GAME_API AuctionEntry
uint32 GetHouseFaction() const { return auctionHouseEntry->FactionID; }
uint32 GetAuctionCut() const;
uint32 GetAuctionOutBid() const;
- void BuildAuctionInfo(std::vector<WorldPackets::AuctionHouse::AuctionItem>& items, bool listAuctionItems) const;
+ void BuildAuctionInfo(std::vector<WorldPackets::AuctionHouse::AuctionItem>& items, bool listAuctionItems, Item* sourceItem = nullptr) const;
void DeleteFromDB(SQLTransaction& trans) const;
void SaveToDB(SQLTransaction& trans) const;
bool LoadFromDB(Field* fields);
@@ -108,10 +108,22 @@ class TC_GAME_API AuctionHouseObject
typedef std::map<uint32, AuctionEntry*> AuctionEntryMap;
+ struct PlayerGetAllThrottleData
+ {
+ uint32 Global;
+ uint32 Cursor;
+ uint32 Tombstone;
+ time_t NextAllowedReplication;
+
+ bool IsReplicationInProgress() const { return Cursor != Tombstone && Global != 0; }
+ };
+
+ typedef std::unordered_map<ObjectGuid, PlayerGetAllThrottleData> PlayerGetAllThrottleMap;
+
uint32 Getcount() const { return uint32(AuctionsMap.size()); }
- AuctionEntryMap::iterator GetAuctionsBegin() {return AuctionsMap.begin();}
- AuctionEntryMap::iterator GetAuctionsEnd() {return AuctionsMap.end();}
+ AuctionEntryMap::iterator GetAuctionsBegin() { return AuctionsMap.begin(); }
+ AuctionEntryMap::iterator GetAuctionsEnd() { return AuctionsMap.end(); }
AuctionEntry* GetAuction(uint32 id) const
{
@@ -130,9 +142,16 @@ class TC_GAME_API AuctionHouseObject
void BuildListAuctionItems(WorldPackets::AuctionHouse::AuctionListItemsResult& packet, Player* player,
std::wstring const& searchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable,
uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32& totalcount);
+ void BuildReplicate(WorldPackets::AuctionHouse::AuctionReplicateResponse& auctionReplicateResult, Player* player,
+ uint32 global, uint32 cursor, uint32 tombstone, uint32 count);
private:
AuctionEntryMap AuctionsMap;
+
+ // Map of throttled players for GetAll, and throttle expiry time
+ // Stored here, rather than player object to maintain persistence after logout
+ PlayerGetAllThrottleMap GetAllThrottleMap;
+
};
class TC_GAME_API AuctionHouseMgr
diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp
index 347ae3d0b03..f0e2d8693b0 100644
--- a/src/server/game/Handlers/AuctionHouseHandler.cpp
+++ b/src/server/game/Handlers/AuctionHouseHandler.cpp
@@ -631,7 +631,7 @@ void WorldSession::HandleAuctionListItems(WorldPackets::AuctionHouse::AuctionLis
wsearchedname, packet.Offset, packet.MinLevel, packet.MaxLevel, packet.OnlyUsable,
packet.InvType, packet.ItemClass, packet.ItemSubclass, packet.Quality, result.TotalCount);
- result.DesiredDelay = 300;
+ result.DesiredDelay = sWorld->getIntConfig(CONFIG_AUCTION_SEARCH_DELAY);
result.OnlyUsable = packet.OnlyUsable;
SendPacket(result.Write());
}
@@ -645,12 +645,24 @@ void WorldSession::HandleAuctionListPendingSales(WorldPackets::AuctionHouse::Auc
void WorldSession::HandleReplicateItems(WorldPackets::AuctionHouse::AuctionReplicateItems& packet)
{
- //@todo implement this properly
+ Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER);
+ if (!creature)
+ {
+ TC_LOG_DEBUG("network", "WORLD: HandleReplicateItems - %s not found or you can't interact with him.", packet.Auctioneer.ToString().c_str());
+ return;
+ }
+
+ // remove fake death
+ if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
+
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+
WorldPackets::AuctionHouse::AuctionReplicateResponse response;
- response.ChangeNumberCursor = packet.ChangeNumberCursor;
- response.ChangeNumberGlobal = packet.ChangeNumberGlobal;
- response.ChangeNumberTombstone = packet.ChangeNumberTombstone;
- response.DesiredDelay = 300;
+
+ auctionHouse->BuildReplicate(response, GetPlayer(), packet.ChangeNumberGlobal, packet.ChangeNumberCursor, packet.ChangeNumberTombstone, packet.Count);
+
+ response.DesiredDelay = sWorld->getIntConfig(CONFIG_AUCTION_SEARCH_DELAY) * 5;
response.Result = 0;
SendPacket(response.Write());
}
diff --git a/src/server/game/Server/Packets/AuctionHousePackets.cpp b/src/server/game/Server/Packets/AuctionHousePackets.cpp
index bb945b396dd..143ba11ddca 100644
--- a/src/server/game/Server/Packets/AuctionHousePackets.cpp
+++ b/src/server/game/Server/Packets/AuctionHousePackets.cpp
@@ -184,10 +184,10 @@ void WorldPackets::AuctionHouse::AuctionRemoveItem::Read()
void WorldPackets::AuctionHouse::AuctionReplicateItems::Read()
{
_worldPacket >> Auctioneer;
- _worldPacket >> Count;
_worldPacket >> ChangeNumberGlobal;
_worldPacket >> ChangeNumberCursor;
_worldPacket >> ChangeNumberTombstone;
+ _worldPacket >> Count;
}
WorldPacket const* WorldPackets::AuctionHouse::AuctionListItemsResult::Write()
@@ -312,12 +312,11 @@ WorldPacket const* WorldPackets::AuctionHouse::AuctionOutBidNotification::Write(
WorldPacket const* WorldPackets::AuctionHouse::AuctionReplicateResponse::Write()
{
- //Todo order
- _worldPacket << int32(ChangeNumberCursor);
- _worldPacket << int32(ChangeNumberGlobal);
+ _worldPacket << int32(Result);
_worldPacket << int32(DesiredDelay);
+ _worldPacket << int32(ChangeNumberGlobal);
+ _worldPacket << int32(ChangeNumberCursor);
_worldPacket << int32(ChangeNumberTombstone);
- _worldPacket << int32(Result);
_worldPacket << int32(Items.size());
for (auto const& item : Items)
diff --git a/src/server/game/Server/Packets/AuctionHousePackets.h b/src/server/game/Server/Packets/AuctionHousePackets.h
index 1183c05da5b..e6aa6faac16 100644
--- a/src/server/game/Server/Packets/AuctionHousePackets.h
+++ b/src/server/game/Server/Packets/AuctionHousePackets.h
@@ -187,10 +187,10 @@ namespace WorldPackets
void Read() override;
ObjectGuid Auctioneer;
- int32 Count = 0;
- int32 ChangeNumberGlobal = 0;
- int32 ChangeNumberCursor = 0;
- int32 ChangeNumberTombstone = 0;
+ uint32 ChangeNumberGlobal = 0;
+ uint32 ChangeNumberCursor = 0;
+ uint32 ChangeNumberTombstone = 0;
+ uint32 Count = 0;
};
class AuctionListPendingSales final : public ClientPacket
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index c77bcfb5962..9d8b88abfe6 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -644,6 +644,13 @@ void World::LoadConfigSettings(bool reload)
m_bool_configs[CONFIG_ADDON_CHANNEL] = sConfigMgr->GetBoolDefault("AddonChannel", true);
m_bool_configs[CONFIG_CLEAN_CHARACTER_DB] = sConfigMgr->GetBoolDefault("CleanCharacterDB", false);
m_int_configs[CONFIG_PERSISTENT_CHARACTER_CLEAN_FLAGS] = sConfigMgr->GetIntDefault("PersistentCharacterCleanFlags", 0);
+ m_int_configs[CONFIG_AUCTION_GETALL_DELAY] = sConfigMgr->GetIntDefault("Auction.GetAllScanDelay", 900);
+ m_int_configs[CONFIG_AUCTION_SEARCH_DELAY] = sConfigMgr->GetIntDefault("Auction.SearchDelay", 300);
+ if (m_int_configs[CONFIG_AUCTION_SEARCH_DELAY] < 100 || m_int_configs[CONFIG_AUCTION_SEARCH_DELAY] > 10000)
+ {
+ TC_LOG_ERROR("server.loading", "Auction.SearchDelay (%i) must be between 100 and 10000. Using default of 300ms", m_int_configs[CONFIG_AUCTION_SEARCH_DELAY]);
+ m_int_configs[CONFIG_AUCTION_SEARCH_DELAY] = 300;
+ }
m_int_configs[CONFIG_CHAT_CHANNEL_LEVEL_REQ] = sConfigMgr->GetIntDefault("ChatLevelReq.Channel", 1);
m_int_configs[CONFIG_CHAT_WHISPER_LEVEL_REQ] = sConfigMgr->GetIntDefault("ChatLevelReq.Whisper", 1);
m_int_configs[CONFIG_CHAT_SAY_LEVEL_REQ] = sConfigMgr->GetIntDefault("ChatLevelReq.Say", 1);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 84b1ba556e3..751caa4b720 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -375,6 +375,8 @@ enum WorldIntConfigs
CONFIG_CHARTER_COST_ARENA_5v5,
CONFIG_NO_GRAY_AGGRO_ABOVE,
CONFIG_NO_GRAY_AGGRO_BELOW,
+ CONFIG_AUCTION_GETALL_DELAY,
+ CONFIG_AUCTION_SEARCH_DELAY,
CONFIG_TALENTS_INSPECTING,
INT_CONFIG_VALUE_COUNT
};
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index edc0e96234d..28dcf903625 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -494,6 +494,24 @@ CleanCharacterDB = 0
PersistentCharacterCleanFlags = 0
#
+# Auction.GetAllScanDelay
+# Description: Sets the minimum time in seconds, a single player character can perform a getall scan.
+# The value is only held in memory so a server restart will clear it.
+# Setting this to zero, will disable GetAll functions completely.
+# Default: 900 - (GetAll scan limited to once every 15mins per player character)
+
+Auction.GetAllScanDelay = 900
+
+#
+# Auction.SearchDelay
+# Description: Sets the minimum time in milliseconds (seconds x 1000), that the client must wait between
+# auction search operations. This can be increased if somehow Auction House activity is causing
+# too much load.
+# Default: 300 - (Time delay between auction searches set to 0.3secs)
+
+Auction.SearchDelay = 300
+
+#
###################################################################################################
###################################################################################################