From e8c358266d5f00e788dcd0f1f8ca188c500c5e11 Mon Sep 17 00:00:00 2001 From: Elson Costa Date: Tue, 21 May 2024 23:50:34 -0300 Subject: [PATCH] wip --- .../players/cyclopedia/player_cyclopedia.cpp | 73 ++++++++++++++----- .../players/cyclopedia/player_cyclopedia.hpp | 68 ++++++++--------- src/enums/player_cyclopedia.hpp | 12 +++ src/game/game.cpp | 12 +++ src/game/game.hpp | 6 ++ src/server/network/protocol/protocolgame.cpp | 50 ++++++++++--- 6 files changed, 156 insertions(+), 65 deletions(-) diff --git a/src/creatures/players/cyclopedia/player_cyclopedia.cpp b/src/creatures/players/cyclopedia/player_cyclopedia.cpp index 9d641938da6..2f281d797bd 100644 --- a/src/creatures/players/cyclopedia/player_cyclopedia.cpp +++ b/src/creatures/players/cyclopedia/player_cyclopedia.cpp @@ -19,15 +19,18 @@ PlayerCyclopedia::PlayerCyclopedia(Player &player) : m_player(player) { } void PlayerCyclopedia::loadSummaryData() { - + loadSummary(); loadRecentKills(); loadDeathHistory(); } +void PlayerCyclopedia::loadSummary() { +} + void PlayerCyclopedia::loadRecentKills() { Benchmark bm_check; - Database &db = Database::getInstance(); + Database &db = g_database(); const std::string &escapedName = db.escapeString(m_player.getName()); DBResult_ptr result = db.storeQuery(fmt::format("SELECT `d`.`time`, `d`.`killed_by`, `d`.`mostdamage_by`, `d`.`unjustified`, `d`.`mostdamage_unjustified`, `p`.`name` FROM `player_deaths` AS `d` INNER JOIN `players` AS `p` ON `d`.`player_id` = `p`.`id` WHERE ((`d`.`killed_by` = {} AND `d`.`is_player` = 1) OR (`d`.`mostdamage_by` = {} AND `d`.`mostdamage_is_player` = 1))", escapedName, escapedName)); if (result) { @@ -47,9 +50,7 @@ void PlayerCyclopedia::loadRecentKills() { } } - std::ostringstream description; - description << "Killed " << name << '.'; - insertPvpKillOnHistory(std::move(description.str()), result->getNumber("time"), status); + insertPvpKillOnHistory(fmt::format("Killed {}.", name), result->getNumber("time"), status); } while (result->next()); } @@ -59,8 +60,7 @@ void PlayerCyclopedia::loadRecentKills() { void PlayerCyclopedia::loadDeathHistory() { Benchmark bm_check; - Database &db = Database::getInstance(); - DBResult_ptr result = db.storeQuery(fmt::format("SELECT `time`, `level`, `killed_by`, `mostdamage_by` FROM `player_deaths` WHERE `player_id` = {} ORDER BY `time` DESC", m_player.getGUID())); + DBResult_ptr result = g_database().storeQuery(fmt::format("SELECT `time`, `level`, `killed_by`, `mostdamage_by` FROM `player_deaths` WHERE `player_id` = {} ORDER BY `time` DESC", m_player.getGUID())); if (result) { do { std::string cause1 = result->getString("killed_by"); @@ -86,6 +86,20 @@ void PlayerCyclopedia::loadDeathHistory() { g_logger().debug("Checking and updating death history of player {} took {} milliseconds.", m_player.getName(), bm_check.duration()); } +void PlayerCyclopedia::updateStoreSummary(uint8_t type, uint16_t count, uint8_t itemType, uint8_t offerId, uint8_t blessId) { + updateAmount(type, count); +} + +uint16_t PlayerCyclopedia::getAmount(uint8_t type) { + auto kv = m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(type))->get("amount"); + return static_cast(kv ? kv->getNumber() : 0); +} + +void PlayerCyclopedia::updateAmount(uint8_t type, uint16_t toAddPoints) { + auto oldPoints = getAmount(type); + m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(type))->set("amount", oldPoints + toAddPoints); +} + std::vector PlayerCyclopedia::getDeathHistory() const { return m_deathHistory; } @@ -102,18 +116,37 @@ void PlayerCyclopedia::insertPvpKillOnHistory(std::string cause, uint32_t timest m_pvpKillsHistory.emplace_back(std::move(cause), timestamp, status); } -void PlayerCyclopedia::updateStoreSummary(uint8_t type, uint16_t count, uint8_t itemType, uint8_t offerId, uint8_t blessId) { +std::map PlayerCyclopedia::getBlessings() const { +} +void insertBlessings(uint8_t bless, uint32_t timestamp) { } -// const std::shared_ptr &PlayerTitle::getSummary(std::string &key) { -// return m_player.kv()->scoped("titles")->scoped("summary")->get(key); -// } -// -// uint16_t PlayerAchievement::getPoints() const { -// return m_player.kv()->scoped("achievements")->get("points")->getNumber(); -// } -// -// void PlayerAchievement::addPoints(uint16_t toAddPoints) { -// auto oldPoints = getPoints(); -// m_player.kv()->scoped("achievements")->set("points", oldPoints + toAddPoints); -// } +std::vector PlayerCyclopedia::getHirelingJobs() const { +} +void insertHirelingJobs(uint8_t job, uint32_t timestamp) { +} + +std::vector PlayerCyclopedia::getHirelingOutfits() const { +} +void insertHirelingOutfits(uint8_t outfit, uint32_t timestamp) { +} + +std::map PlayerCyclopedia::getHouseItems() const { + auto type = static_cast(Summary_t::HOUSE_ITEMS); + auto kvItem = m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(type)); + + std::map items = {}; + for (const auto &itemId : kvItem->keys()) { + auto kv = kvItem->scoped(itemId)->get("amount"); + auto amount = static_cast(kv ? kv->getNumber() : 0); + items[std::stoull(itemId)] += amount; + } + + return items; +} + +void PlayerCyclopedia::insertHouseItems(uint32_t itemId, uint16_t amount) { + auto type = static_cast(Summary_t::HOUSE_ITEMS); + auto oldAmount = static_cast(m_houseItems[itemId]); + m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(type))->scoped(fmt::format("{}", itemId))->set("amount", oldAmount + amount); +} diff --git a/src/creatures/players/cyclopedia/player_cyclopedia.hpp b/src/creatures/players/cyclopedia/player_cyclopedia.hpp index a0ad59fed5d..3ed6d3f6de0 100644 --- a/src/creatures/players/cyclopedia/player_cyclopedia.hpp +++ b/src/creatures/players/cyclopedia/player_cyclopedia.hpp @@ -9,68 +9,64 @@ #pragma once +#include +#include +#include + class Player; class KV; struct Summary { - uint16_t m_storeXpBoosts = 0; - uint16_t m_dailyRewardCollections = 0; + uint16_t m_xpBoosts = 0; + uint16_t m_preyWildcards = 0; + uint16_t m_instantRewards = 0; + uint16_t m_charmsExpansions = 0; uint16_t m_hirelings = 0; - uint16_t m_preyCards = 0; - uint16_t m_charms = 0; - uint16_t m_goshnar = 0; - uint16_t m_drome = 0; - uint16_t m_loginStreak = 0; - uint16_t m_taskHuntingPoints = 0; - uint16_t m_mapAreaDiscoveredPercentage = 0; - - std::vector m_hirelingOutfits; - std::vector m_hirelingJobs; - std::map m_blessings; - Summary(uint16_t mStoreXpBoosts, uint16_t mDailyRewardCollections, uint16_t mHirelings, uint16_t mPreyCards, uint16_t mCharms, uint16_t mGoshnar, uint16_t mDrome, uint16_t mLoginStreak, uint16_t mTaskHuntingPoints, uint16_t mMapAreaDiscoveredPercentage, const std::vector &mHirelingOutfits, const std::vector &mHirelingJobs, const std::map &mBlessings) : - m_storeXpBoosts(mStoreXpBoosts), m_dailyRewardCollections(mDailyRewardCollections), m_hirelings(mHirelings), m_preyCards(mPreyCards), m_charms(mCharms), m_goshnar(mGoshnar), m_drome(mDrome), m_loginStreak(mLoginStreak), m_taskHuntingPoints(mTaskHuntingPoints), m_mapAreaDiscoveredPercentage(mMapAreaDiscoveredPercentage), m_hirelingOutfits(mHirelingOutfits), m_hirelingJobs(mHirelingJobs), m_blessings(mBlessings) { } + Summary(uint16_t mXpBoosts, uint16_t mPreyWildcards, uint16_t mInstantRewards, uint16_t mCharmsExpansions, uint16_t mHirelings) : + m_xpBoosts(mXpBoosts), m_preyWildcards(mPreyWildcards), m_instantRewards(mInstantRewards), m_charmsExpansions(mCharmsExpansions), m_hirelings(mHirelings) { } }; class PlayerCyclopedia { public: explicit PlayerCyclopedia(Player &player); - Summary getSummary() { - return Summary(m_storeXpBoosts, m_dailyRewardCollections, m_hirelings, m_preyCards, m_charms, m_goshnar, m_drome, m_loginStreak, m_taskHuntingPoints, m_mapAreaDiscoveredPercentage, m_hirelingOutfits, m_hirelingJobs, m_blessings); - } void loadSummaryData(); + void loadSummary(); void loadRecentKills(); void loadDeathHistory(); + void updateStoreSummary(uint8_t type, uint16_t count = 1, uint8_t itemType = 0, uint8_t offerId = 0, uint8_t blessId = 0); + uint16_t getAmount(uint8_t type); + void updateAmount(uint8_t type, uint16_t toAddPoints); + [[nodiscard]] std::vector getDeathHistory() const; void insertDeathOnHistory(std::string cause, uint32_t timestamp); + [[nodiscard]] std::vector getPvpKillsHistory() const; void insertPvpKillOnHistory(std::string cause, uint32_t timestamp, uint8_t status); - void updateStoreSummary(uint8_t type, uint16_t count = 1, uint8_t itemType = 0, uint8_t offerId = 0, uint8_t blessId = 0); + const Summary &getSummary() { + return Summary(getAmount(Summary_t::BOOSTS), getAmount(Summary_t::PREY_WILDCARDS), getAmount(Summary_t::INSTANT_REWARDS), getAmount(Summary_t::CHARM_EXPANSIONS), getAmount(Summary_t::HIRELINGS)); + } + [[nodiscard]] std::map getBlessings() const; + void insertBlessings(uint8_t bless, uint32_t timestamp); -private: - uint16_t m_storeXpBoosts = 0; - uint16_t m_dailyRewardCollections = 0; - uint16_t m_hirelings = 0; - uint16_t m_preyCards = 0; - uint16_t m_charms = 0; - uint16_t m_goshnar = 0; - uint16_t m_drome = 0; - uint16_t m_loginStreak = 0; - uint16_t m_taskHuntingPoints = 0; - uint16_t m_mapAreaDiscoveredPercentage = 0; + [[nodiscard]] std::vector getHirelingJobs() const; + void insertHirelingJobs(uint8_t job, uint32_t timestamp); - std::vector m_hirelingOutfits; - std::vector m_hirelingJobs; - std::map m_blessings; + [[nodiscard]] std::vector getHirelingOutfits() const; + void insertHirelingOutfits(uint8_t outfit, uint32_t timestamp); - // StashItemList houseItems; - // std::map> m_accountLevelSummary; + [[nodiscard]] std::map getHouseItems() const; + void insertHouseItems(uint32_t itemId, uint16_t amount); +private: std::vector m_deathHistory; std::vector m_pvpKillsHistory; - + std::map m_blessings; + std::vector m_hirelingJobs; + std::vector m_hirelingOutfits; + std::map m_houseItems; Player &m_player; }; diff --git a/src/enums/player_cyclopedia.hpp b/src/enums/player_cyclopedia.hpp index f0637011a19..2526b628bde 100644 --- a/src/enums/player_cyclopedia.hpp +++ b/src/enums/player_cyclopedia.hpp @@ -36,3 +36,15 @@ enum CyclopediaTitle_t : uint8_t { MAP, OTHERS, }; + +enum Summary_t : uint8_t { + BOOSTS = 1, + PREY_SLOTS, + PREY_WILDCARDS, + INSTANT_REWARDS, + CHARM_EXPANSIONS, + HIRELINGS, + HIRELING_JOBS, + HIRELING_OUTFITS, + HOUSE_ITEMS, +}; diff --git a/src/game/game.cpp b/src/game/game.cpp index f7e78ebc148..9980c7dcec1 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -359,6 +359,18 @@ Game::Game() { HighscoreCategory("Fishing", static_cast(HighscoreCategories_t::FISHING)), HighscoreCategory("Magic Level", static_cast(HighscoreCategories_t::MAGIC_LEVEL)) }; + + m_summaryCategories = { + { static_cast(Summary_t::BOOSTS), "xp-boosts" }, + { static_cast(Summary_t::PREY_SLOTS), "prey-slots" }, + { static_cast(Summary_t::PREY_WILDCARDS), "prey-wildcards" }, + { static_cast(Summary_t::INSTANT_REWARDS), "instant-rewards" }, + { static_cast(Summary_t::CHARM_EXPANSIONS), "charm-expansions" }, + { static_cast(Summary_t::HIRELINGS), "hirelings" }, + { static_cast(Summary_t::HIRELING_JOBS), "hirelings-jobs" }, + { static_cast(Summary_t::HIRELING_OUTFITS), "hireling-outfits" }, + { static_cast(Summary_t::HOUSE_ITEMS), "house-items" }, + }; } Game::~Game() = default; diff --git a/src/game/game.hpp b/src/game/game.hpp index 554c418a2c8..b35a4dfb61d 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -732,6 +732,10 @@ class Game { Title getTitleById(uint8_t id); Title getTitleByName(const std::string &name); + const std::string &getSummaryKeyByType(uint8_t type) { + return m_summaryCategories[type]; + } + private: std::map m_achievements; std::map m_achievementsNameToId; @@ -742,6 +746,8 @@ class Game { std::vector m_highscoreCategories; std::unordered_map m_highscoreCategoriesNames; + std::unordered_map m_summaryCategories; + std::map forgeMonsterEventIds; std::unordered_set fiendishMonsters; std::unordered_set influencedMonsters; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index cd2514fba12..6fdbc421512 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -3941,19 +3941,51 @@ void ProtocolGame::sendCyclopediaCharacterStoreSummary() { // getBlessingsObtained auto blessings = player->getBlessingNames(); - msg.addByte(static_cast(blessings.size())); // getBlessingsObtained + msg.addByte(static_cast(blessings.size())); for (const auto &it : blessings) { msg.addString(it.second, "ProtocolGame::sendCyclopediaCharacterStoreSummary - blessing.name"); - msg.addByte(static_cast((cyclopediaSummary.m_blessings)[it.first])); + msg.addByte(static_cast((player->cyclopedia()->getBlessings())[it.first])); } - msg.addByte(0x00); // getTaskHuntingSlotById - msg.addByte(0x00); // getPreyCardsObtained - msg.addByte(0x00); // getRewardCollectionObtained + + uint8_t preySlotsUnlocked = 0; + // Prey third slot unlocked + if (const auto &slotP = player->getPreySlotById(PreySlot_Three); + slotP && slotP->state != PreyDataState_Locked) { + preySlotsUnlocked++; + } + // Task hunting third slot unlocked + if (const auto &slotH = player->getTaskHuntingSlotById(PreySlot_Three); + slotH && slotH->state != PreyTaskDataState_Locked) { + preySlotsUnlocked++; + } + msg.addByte(preySlotsUnlocked); // getPreySlotById + getTaskHuntingSlotById + + msg.addByte(cyclopediaSummary.m_preyWildcards); // getPreyCardsObtained + msg.addByte(cyclopediaSummary.m_instantRewards); // getRewardCollectionObtained msg.addByte(player->hasCharmExpansion() ? 0x01 : 0x00); - msg.addByte(0x00); // getHirelingsObtained - msg.addByte(0x00); // getHirelinsJobsObtained - msg.addByte(0x00); // getHirelinsOutfitsObtained - msg.add(0); // getHouseItemsObtained + msg.addByte(cyclopediaSummary.m_hirelings); // getHirelingsObtained + + auto jobs = player->cyclopedia()->getHirelingJobs(); + msg.addByte(jobs.size()); + for (const auto job_it : jobs) { + msg.addByte(job_it); + } + + auto outfits = player->cyclopedia()->getHirelingOutfits(); + msg.addByte(outfits.size()); + for (const auto outfit_it : outfits) { + msg.addByte(outfit_it); + } + + auto houseItems = player->cyclopedia()->getHouseItems(); + msg.add(houseItems.size()); + for (const auto &hItem_it : houseItems) { + const ItemType &it = Item::items[hItem_it.first]; + msg.add(hItem_it.first); // Item ID + msg.addString(it.name, "ProtocolGame::sendCyclopediaCharacterStoreSummary - houseItem.name"); + msg.addByte(hItem_it.second); + } + writeToOutputBuffer(msg); }