diff --git a/src/game/game.cpp b/src/game/game.cpp index a0028c1aa18..5b973f3776a 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -296,6 +296,7 @@ void Game::start(ServiceManager* manager) { g_dispatcher().cycleEvent( EVENT_LUA_GARBAGE_COLLECTION, [this] { g_luaEnvironment().collectGarbage(); }, "Calling GC" ); + g_dispatcher().cycleEvent(EVENT_REFRESH_MARKET_PRICES, std::bind_front(&Game::loadItemsPrice, this), "Game::loadItemsPrice"); } GameState_t Game::getGameState() const { @@ -388,7 +389,7 @@ void Game::setGameState(GameState_t newState) { } bool Game::loadItemsPrice() { - itemsSaleCount = 0; + IOMarket::getInstance().updateStatistics(); std::ostringstream query, marketQuery; query << "SELECT DISTINCT `itemtype` FROM `market_offers`;"; @@ -398,20 +399,19 @@ bool Game::loadItemsPrice() { return false; } - do { - marketQuery.str(std::string()); - uint16_t itemId = result->getNumber("itemtype"); - marketQuery << "SELECT `price`, `tier` FROM `market_offers` WHERE `itemtype` = " << itemId << " ORDER BY `price` DESC LIMIT 1"; - DBResult_ptr marketOffersResult = db.storeQuery(marketQuery.str()); - if (marketOffersResult) { - std::map tierAndCount; - auto tier = marketOffersResult->getNumber("tier"); - auto price = marketOffersResult->getNumber("price"); - tierAndCount[tier] = price; - itemsPriceMap[itemId] = tierAndCount; - itemsSaleCount++; - } - } while (result->next()); + auto stats = IOMarket::getInstance().getPurchaseStatistics(); + for (const auto &[itemId, itemStats] : stats) { + std::map tierToPrice; + for (const auto &[tier, tierStats] : itemStats) { + auto averagePrice = tierStats.totalPrice / tierStats.numTransactions; + tierToPrice[tier] = averagePrice; + } + itemsPriceMap[itemId] = tierToPrice; + } + auto offers = IOMarket::getInstance().getActiveOffers(MARKETACTION_BUY); + for (const auto &offer : offers) { + itemsPriceMap[offer.itemId][offer.tier] = std::max(itemsPriceMap[offer.itemId][offer.tier], offer.price); + } return true; } @@ -8523,17 +8523,6 @@ void Game::playerCreateMarketOffer(uint32_t playerId, uint8_t type, uint16_t ite IOMarket::createOffer(player->getGUID(), static_cast(type), it.id, amount, price, tier, anonymous); - // uint8_t = tier, uint64_t price - std::map tierAndPriceMap; - tierAndPriceMap[tier] = price; - auto ColorItem = itemsPriceMap.find(it.id); - if (ColorItem == itemsPriceMap.end()) { - itemsPriceMap[it.id] = tierAndPriceMap; - itemsSaleCount++; - } else if (auto priceIt = ColorItem->second.find(tier); priceIt->second < price) { - itemsPriceMap[it.id] = tierAndPriceMap; - } - const MarketOfferList &buyOffers = IOMarket::getActiveOffers(MARKETACTION_BUY, it.id, tier); const MarketOfferList &sellOffers = IOMarket::getActiveOffers(MARKETACTION_SELL, it.id, tier); player->sendMarketBrowseItem(it.id, buyOffers, sellOffers, tier); diff --git a/src/game/game.hpp b/src/game/game.hpp index 0ae4065ab06..bbf2e66088c 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -45,6 +45,7 @@ static constexpr int32_t EVENT_DECAYINTERVAL = 250; static constexpr int32_t EVENT_DECAY_BUCKETS = 4; static constexpr int32_t EVENT_FORGEABLEMONSTERCHECKINTERVAL = 300000; static constexpr int32_t EVENT_LUA_GARBAGE_COLLECTION = 60000 * 10; // 10min +static constexpr int32_t EVENT_REFRESH_MARKET_PRICES = 60000; // 1min static constexpr std::chrono::minutes CACHE_EXPIRATION_TIME { 10 }; // 10min static constexpr std::chrono::minutes HIGHSCORE_CACHE_EXPIRATION_TIME { 10 }; // 10min @@ -184,9 +185,6 @@ class Game { uint32_t getPlayersRecord() const { return playersRecord; } - uint16_t getItemsPriceCount() const { - return itemsSaleCount; - } void addItemsClassification(ItemClassification* itemsClassification) { itemsClassifications.push_back(itemsClassification); @@ -860,7 +858,6 @@ class Game { uint32_t motdNum = 0; std::map> itemsPriceMap; - uint16_t itemsSaleCount; std::vector itemsClassifications; diff --git a/src/io/iomarket.cpp b/src/io/iomarket.cpp index ad045998375..f308e10e687 100644 --- a/src/io/iomarket.cpp +++ b/src/io/iomarket.cpp @@ -26,6 +26,35 @@ uint8_t IOMarket::getTierFromDatabaseTable(const std::string &string) { return tier; } +MarketOfferList IOMarket::getActiveOffers(MarketAction_t action) { + MarketOfferList offerList; + + std::ostringstream query; + query << "SELECT `id`, `amount`, `price`, `tier`, `created`, `anonymous`, (SELECT `name` FROM `players` WHERE `id` = `player_id`) AS `player_name` FROM `market_offers` WHERE `sale` = " << action; + + DBResult_ptr result = Database::getInstance().storeQuery(query.str()); + if (!result) { + return offerList; + } + + const int32_t marketOfferDuration = g_configManager().getNumber(MARKET_OFFER_DURATION, __FUNCTION__); + + do { + MarketOffer offer; + offer.amount = result->getNumber("amount"); + offer.price = result->getNumber("price"); + offer.timestamp = result->getNumber("created") + marketOfferDuration; + offer.counter = result->getNumber("id") & 0xFFFF; + if (result->getNumber("anonymous") == 0) { + offer.playerName = result->getString("player_name"); + } else { + offer.playerName = "Anonymous"; + } + offer.tier = getTierFromDatabaseTable(result->getString("tier")); + offerList.push_back(offer); + } while (result->next()); + return offerList; +} MarketOfferList IOMarket::getActiveOffers(MarketAction_t action, uint16_t itemId, uint8_t tier) { MarketOfferList offerList; diff --git a/src/io/iomarket.hpp b/src/io/iomarket.hpp index f192acca5fe..b02fba0ce6a 100644 --- a/src/io/iomarket.hpp +++ b/src/io/iomarket.hpp @@ -23,6 +23,7 @@ class IOMarket { return inject(); } + static MarketOfferList getActiveOffers(MarketAction_t action); static MarketOfferList getActiveOffers(MarketAction_t action, uint16_t itemId, uint8_t tier); static MarketOfferList getOwnOffers(MarketAction_t action, uint32_t playerId); static HistoryMarketOfferList getOwnHistory(MarketAction_t action, uint32_t playerId); diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index b0f3c39e573..408f6c12904 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -7802,18 +7802,21 @@ void ProtocolGame::sendItemsPrice() { NetworkMessage msg; msg.addByte(0xCD); - msg.add(g_game().getItemsPriceCount()); - if (g_game().getItemsPriceCount() > 0) { - for (const auto &[itemId, tierAndPriceMap] : g_game().getItemsPrice()) { - for (const auto &[tier, price] : tierAndPriceMap) { - msg.add(itemId); - if (Item::items[itemId].upgradeClassification > 0) { - msg.addByte(tier); - } - msg.add(price); + auto countBuffer = msg.getBufferPosition(); + uint16_t count = 0; + msg.skipBytes(2); + for (const auto &[itemId, tierAndPriceMap] : g_game().getItemsPrice()) { + for (const auto &[tier, price] : tierAndPriceMap) { + msg.add(itemId); + if (Item::items[itemId].upgradeClassification > 0) { + msg.addByte(tier); } + msg.add(price); + count++; } } + msg.setBufferPosition(countBuffer); + msg.add(count); writeToOutputBuffer(msg); }