From 381f99bea9d5b7f8f1de7fa1026bb7179831f75e Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:23:40 -0300 Subject: [PATCH] fix: store transfer history --- src/account/account.cpp | 18 ++++++ src/account/account.hpp | 11 ++++ src/account/account_repository.hpp | 9 +++ src/account/account_repository_db.cpp | 36 ++++++++++++ src/account/account_repository_db.hpp | 9 +++ src/creatures/players/player.hpp | 6 +- src/game/game.cpp | 61 +++++++++++++------- src/io/functions/iologindata_load_player.cpp | 6 +- src/io/functions/iologindata_save_player.cpp | 4 +- src/server/network/protocol/protocolgame.cpp | 4 +- 10 files changed, 134 insertions(+), 30 deletions(-) diff --git a/src/account/account.cpp b/src/account/account.cpp index 1ca7e9d3350..59bf2af229c 100644 --- a/src/account/account.cpp +++ b/src/account/account.cpp @@ -162,6 +162,24 @@ void Account::registerCoinTransaction(const uint8_t &transactionType, const uint } } +void Account::registerStoreTransaction(const uint8_t &type, const uint32_t &amount, const uint8_t &coinType, const std::string &description, const time_t &time) { + if (!m_accLoaded) { + return; + } + + if (description.empty()) { + return; + } + + if (!g_accountRepository().registerStoreTransaction(m_account.id, type, amount, coinType, description, time)) { + g_logger().error( + "Failed to register transaction: 'account:[{}], transaction " + "type:[{}], coins:[{}], coin type:[{}], description:[{}], time:[{}]", + m_account.id, type, amount, type, description, time + ); + } +} + [[nodiscard]] uint32_t Account::getID() const { return m_account.id; }; diff --git a/src/account/account.hpp b/src/account/account.hpp index d968ba8ddfb..74560407282 100644 --- a/src/account/account.hpp +++ b/src/account/account.hpp @@ -53,6 +53,17 @@ class Account { */ void registerCoinTransaction(const uint8_t &transactionType, const uint8_t &type, const uint32_t &amount, const std::string &detail); + /** + * @brief Registers a store transaction. + * + * @param type Type of history entry + * @param coinType Type of the coin + * @param amount Amount of coins to be registered + * @param description Detail of the transaction + * @param time Time of the transaction + */ + void registerStoreTransaction(const uint8_t &type, const uint32_t &amount, const uint8_t &coinType, const std::string &description, const time_t &time); + /*************************************************************************** * Account Load/Save **************************************************************************/ diff --git a/src/account/account_repository.hpp b/src/account/account_repository.hpp index 0d4dcc7abcf..93fe240b3ed 100644 --- a/src/account/account_repository.hpp +++ b/src/account/account_repository.hpp @@ -38,6 +38,15 @@ class AccountRepository { const uint8_t &coinType, const std::string &description ) = 0; + + virtual bool registerStoreTransaction( + const uint32_t &id, + uint8_t type, + int32_t amount, + const uint8_t &coinType, + const std::string &description, + const time_t &time + ) = 0; }; constexpr auto g_accountRepository = AccountRepository::getInstance; diff --git a/src/account/account_repository_db.cpp b/src/account/account_repository_db.cpp index b150a636a97..b9b27fa6dee 100644 --- a/src/account/account_repository_db.cpp +++ b/src/account/account_repository_db.cpp @@ -148,6 +148,42 @@ bool AccountRepositoryDB::registerCoinsTransaction( return successful; }; +bool AccountRepositoryDB::registerStoreTransaction( + const uint32_t &id, + uint8_t type, + int32_t amount, + const uint8_t &coinType, + const std::string &description, + const time_t &time +) { + + bool successful = g_database().executeQuery( + fmt::format( + "INSERT INTO `store_history` (`account_id`, `description`, `coin_amount`, `coin_type`, `type`, `time`) VALUES ({}, {}, {}, {}, {}, {})", + id, + g_database().escapeString(description), + amount, + coinType, + type, + time + ) + ); + + if (!successful) { + g_logger().error( + "Error registering coin transaction! account_id:[{}], type:[{}], coin_type:[{}], coins:[{}], description:[{}], time:[{}]", + id, + type, + coinType, + amount, + g_database().escapeString(description), + time + ); + } + + return successful; +}; + bool AccountRepositoryDB::loadAccountPlayers(AccountInfo &acc) { auto result = g_database().storeQuery( fmt::format("SELECT `name`, `deletion` FROM `players` WHERE `account_id` = {} ORDER BY `name` ASC", acc.id) diff --git a/src/account/account_repository_db.hpp b/src/account/account_repository_db.hpp index 651600e3bc4..bd97a60765a 100644 --- a/src/account/account_repository_db.hpp +++ b/src/account/account_repository_db.hpp @@ -32,6 +32,15 @@ class AccountRepositoryDB final : public AccountRepository { const std::string &description ) override; + bool registerStoreTransaction( + const uint32_t &id, + uint8_t type, + int32_t amount, + const uint8_t &coinType, + const std::string &description, + const time_t &time + ) override; + private: const std::map coinTypeToColumn; bool load(const std::string &query, AccountInfo &acc); diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 8af6f464f72..db2980f2bed 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -96,9 +96,9 @@ struct ForgeHistory { struct StoreHistory { time_t createdAt; - uint16_t coinAmount = 0; - uint16_t coinType = 0; - uint16_t historyType = 0; + int32_t coinAmount = 0; + uint8_t coinType = 0; + uint8_t historyType = 0; std::string description; }; diff --git a/src/game/game.cpp b/src/game/game.cpp index 2bf4efab248..fc6f8986e00 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10293,12 +10293,9 @@ void Game::playerCoinTransfer(uint32_t playerId, std::string receptorName, uint3 return; } - std::shared_ptr playerReceptor = getPlayerByName(receptorName); + std::shared_ptr playerReceptor = getPlayerByName(receptorName, true); if (!playerReceptor) { - playerReceptor = std::make_shared(nullptr); - if (!IOLoginData::loadPlayerByName(playerReceptor, receptorName)) { - return; - } + return; } if (playerDonator == playerReceptor || playerDonator->getAccount() == playerReceptor->getAccount()) { @@ -10312,13 +10309,38 @@ void Game::playerCoinTransfer(uint32_t playerId, std::string receptorName, uint3 } std::string historyDesc = fmt::format("{} gifted to {}", playerDonator->getName(), playerReceptor->getName()); - playerDonator->getAccount()->removeCoins(enumToValue(CoinType::Transferable), static_cast(coinAmount), historyDesc); - playerReceptor->getAccount()->addCoins(enumToValue(CoinType::Transferable), static_cast(coinAmount), historyDesc); + playerDonator->getAccount()->removeCoins(enumToValue(CoinType::Transferable), coinAmount, historyDesc); + playerReceptor->getAccount()->addCoins(enumToValue(CoinType::Transferable), coinAmount, historyDesc); + + StoreHistory tempHistory; + tempHistory.description = historyDesc; + tempHistory.coinType = enumToValue(CoinType::Transferable); + tempHistory.historyType = enumToValue(HistoryTypes_t::NONE); + tempHistory.coinAmount = static_cast(coinAmount * -1); + tempHistory.createdAt = getTimeNow(); + + playerDonator->setStoreHistory(tempHistory); if (playerReceptor->isOffline()) { - IOLoginData::savePlayer(playerReceptor); + std::shared_ptr newPlayerReceptor; + const auto playersAccountVector = getPlayersByAccount(playerReceptor->getAccount()); + for (const auto player : playersAccountVector) { + if (player->isOnline()) { + newPlayerReceptor = player; + } + } + + if (newPlayerReceptor) { + tempHistory.coinAmount = coinAmount; + newPlayerReceptor->sendCoinBalance(); + newPlayerReceptor->setStoreHistory(tempHistory); + } else { + playerReceptor->getAccount()->registerStoreTransaction(tempHistory.historyType, coinAmount, tempHistory.coinType, historyDesc, tempHistory.createdAt); + } } else { + tempHistory.coinAmount = coinAmount; playerReceptor->sendCoinBalance(); + playerReceptor->setStoreHistory(tempHistory); } playerDonator->openStore(); @@ -10623,7 +10645,7 @@ void Game::playerBuyStoreOffer(uint32_t playerId, const Offer* offer, std::strin StoreHistory tempHistory; tempHistory.description = offer->getOfferName(); - tempHistory.coinAmount = offerPrice; + tempHistory.coinAmount = static_cast(offerPrice * -1); tempHistory.createdAt = getTimeNow(); player->sendStoreSuccess(returnmessage); @@ -10756,27 +10778,26 @@ bool Game::processNameChangeOffer(std::shared_ptr player, std::string &n trimString(newName); auto isValidName = validateName(newName); - if (isValidName != VALID) { return false; } - std::ostringstream query; - Database &db = Database::getInstance(); - query << "SELECT `id` FROM `player` WHERE `name` = " << db.escapeString(newName); - if (db.storeQuery(query.str())) { - return false; - } + capitalizeWords(newName); - if (g_monsters().getMonsterType(newName)) { + if (g_monsters().getMonsterType(newName, true)) { return false; } else if (getNpcByName(newName)) { return false; } - capitalizeWords(newName); - query << "UPDATE `players` SET `name` = " << db.escapeString(newName) << "WHERE `id` = " << player->getGUID(); - if (!db.executeQuery(query.str())) { + Database &db = Database::getInstance(); + DBResult_ptr result = db.storeQuery(fmt::format("SELECT `id` FROM `players` WHERE `name` = {}", db.escapeString(newName))); + if (result) { + return false; + } + + std::string query = fmt::format("UPDATE `players` SET `name` = {} WHERE `id` = {}", db.escapeString(newName), player->getGUID()); + if (!db.executeQuery(query)) { return false; } diff --git a/src/io/functions/iologindata_load_player.cpp b/src/io/functions/iologindata_load_player.cpp index fe8538a5adb..b954def2cb3 100644 --- a/src/io/functions/iologindata_load_player.cpp +++ b/src/io/functions/iologindata_load_player.cpp @@ -840,9 +840,9 @@ void IOLoginDataLoad::loadPlayerStoreHistory(std::shared_ptr player, DBR do { StoreHistory history; history.description = result->getString("description"); - history.coinAmount = result->getNumber("coin_amount"); - history.coinType = result->getNumber("coin_type"); - history.historyType = result->getNumber("type"); + history.coinAmount = result->getNumber("coin_amount"); + history.coinType = result->getNumber("coin_type"); + history.historyType = result->getNumber("type"); history.createdAt = result->getNumber("time"); player->setStoreHistory(history); } while (result->next()); diff --git a/src/io/functions/iologindata_save_player.cpp b/src/io/functions/iologindata_save_player.cpp index 54b06a27c1a..2929a445f58 100644 --- a/src/io/functions/iologindata_save_player.cpp +++ b/src/io/functions/iologindata_save_player.cpp @@ -740,8 +740,8 @@ bool IOLoginDataSave::savePlayerStoreHistory(std::shared_ptr player) { query << player->getAccountId() << ',' << descriptionString << ',' << historyEntry.coinAmount << ',' - << historyEntry.coinType << ',' - << historyEntry.historyType << ',' + << static_cast(historyEntry.coinType) << ',' + << static_cast(historyEntry.historyType) << ',' << historyEntry.createdAt; if (!insertQuery.addRow(query)) { diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 642d4544285..b579f01ff5d 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -9239,10 +9239,10 @@ void ProtocolGame::sendStoreHistory(uint32_t page) { if (historyPageToSend > 0) { for (const auto &history : historyPerPage) { - msg.add(0x00); + msg.add(0x00); // Id? msg.add(static_cast(history.createdAt)); - msg.addByte(0x00); + msg.addByte(history.historyType); msg.add(history.coinAmount); msg.addByte(history.coinType);