Skip to content

Commit

Permalink
fixed move Recent Kills and Death History functions from 'protocolgam…
Browse files Browse the repository at this point in the history
…e.cpp' to 'player_cyclopedia.cpp'.
  • Loading branch information
elsongabriel committed May 27, 2024
1 parent c0c8514 commit 216f870
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 147 deletions.
4 changes: 3 additions & 1 deletion src/creatures/creatures_definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,9 @@ enum CombatType_t : uint8_t {
};

enum PlayerAsyncOngoingTaskFlags : uint64_t {
PlayerAsyncTask_Highscore = 1 << 0
PlayerAsyncTask_Highscore = 1 << 0,
PlayerAsyncTask_RecentDeaths = 1 << 1,
PlayerAsyncTask_RecentPvPKills = 1 << 2
};

enum PartyAnalyzer_t : uint8_t {
Expand Down
141 changes: 80 additions & 61 deletions src/creatures/players/cyclopedia/player_cyclopedia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,86 +9,125 @@

#include "pch.hpp"

#include "player_cyclopedia.hpp"

#include "database/databasetasks.hpp"
#include "creatures/players/player.hpp"
#include "player_cyclopedia.hpp"
#include "game/game.hpp"
#include "kv/kv.hpp"

PlayerCyclopedia::PlayerCyclopedia(Player &player) :
m_player(player) { }

void PlayerCyclopedia::loadSummaryData() {
loadSummary();
loadRecentKills();
loadDeathHistory();
}

void PlayerCyclopedia::loadSummary() {
DBResult_ptr result = g_database().storeQuery(fmt::format("SELECT COUNT(*) as `count` FROM `player_hirelings` WHERE `player_id` = {}", m_player.getGUID()));
auto kvScoped = m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(static_cast<uint8_t>(Summary_t::HIRELINGS)));
if (result && !kvScoped->get("amount").has_value()) {
kvScoped->set("amount", result->getNumber<int16_t>("count"));
}
}

void PlayerCyclopedia::loadRecentKills() {
void PlayerCyclopedia::loadDeathHistory(uint16_t page, uint16_t entriesPerPage) {
Benchmark bm_check;
uint32_t offset = static_cast<uint32_t>(page - 1) * entriesPerPage;
auto query = fmt::format("SELECT `time`, `level`, `killed_by`, `mostdamage_by`, (select count(*) FROM `player_deaths` WHERE `player_id` = {}) as `entries` FROM `player_deaths` WHERE `player_id` = {} AND `time` >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY)) ORDER BY `time` DESC LIMIT {}, {}", m_player.getGUID(), m_player.getGUID(), offset, entriesPerPage);

uint32_t playerID = m_player.getID();
std::function<void(DBResult_ptr, bool)> callback = [playerID, page, entriesPerPage](const DBResult_ptr &result, bool) {
std::shared_ptr<Player> player = g_game().getPlayerByID(playerID);
if (!player) {
return;
}

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) {
player->resetAsyncOngoingTask(PlayerAsyncTask_RecentDeaths);
if (!result) {
player->sendCyclopediaCharacterRecentDeaths(0, 0, {});
return;
}

auto pages = result->getNumber<uint32_t>("entries");
pages += entriesPerPage - 1;
pages /= entriesPerPage;

std::vector<RecentDeathEntry> entries;
entries.reserve(result->countResults());
do {
std::string cause1 = result->getString("killed_by");
std::string cause2 = result->getString("mostdamage_by");
std::string name = result->getString("name");

uint8_t status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_JUSTIFIED;
if (m_player.getName() == cause1) {
if (result->getNumber<uint32_t>("unjustified") == 1) {
status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_UNJUSTIFIED;
}
} else if (m_player.getName() == cause2) {
if (result->getNumber<uint32_t>("mostdamage_unjustified") == 1) {
status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_UNJUSTIFIED;
std::ostringstream cause;
cause << "Died at Level " << result->getNumber<uint32_t>("level") << " by";
if (!cause1.empty()) {
cause << getArticle(cause1) << cause1;
}

if (!cause2.empty()) {
if (!cause1.empty()) {
cause << " and";
}
cause << getArticle(cause2) << cause2;
}
cause << '.';

insertPvpKillOnHistory(fmt::format("Killed {}.", name), result->getNumber<uint32_t>("time"), status);
entries.emplace_back(std::move(cause.str()), result->getNumber<uint32_t>("time"));
} while (result->next());
}
player->sendCyclopediaCharacterRecentDeaths(page, static_cast<uint16_t>(pages), entries);
};
g_databaseTasks().store(query, callback);
m_player.addAsyncOngoingTask(PlayerAsyncTask_RecentDeaths);

g_logger().debug("Checking and updating recent kill of player {} took {} milliseconds.", m_player.getName(), bm_check.duration());
g_logger().debug("Loading death history from the player {} took {} milliseconds.", m_player.getName(), bm_check.duration());
}

void PlayerCyclopedia::loadDeathHistory() {
void PlayerCyclopedia::loadRecentKills(uint16_t page, uint16_t entriesPerPage) {
Benchmark bm_check;

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) {
const std::string &escapedName = g_database().escapeString(m_player.getName());
uint32_t offset = static_cast<uint32_t>(page - 1) * entriesPerPage;
auto query = fmt::format("SELECT `d`.`time`, `d`.`killed_by`, `d`.`mostdamage_by`, `d`.`unjustified`, `d`.`mostdamage_unjustified`, `p`.`name`, (select count(*) FROM `player_deaths` WHERE ((`killed_by` = {} AND `is_player` = 1) OR (`mostdamage_by` = {} AND `mostdamage_is_player` = 1))) as `entries` 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)) AND `time` >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY)) ORDER BY `time` DESC LIMIT {}, {}", escapedName, escapedName, escapedName, escapedName, offset, entriesPerPage);

uint32_t playerID = m_player.getID();
std::function<void(DBResult_ptr, bool)> callback = [playerID, page, entriesPerPage](const DBResult_ptr &result, bool) {
std::shared_ptr<Player> player = g_game().getPlayerByID(playerID);
if (!player) {
return;
}

player->resetAsyncOngoingTask(PlayerAsyncTask_RecentPvPKills);
if (!result) {
player->sendCyclopediaCharacterRecentPvPKills(0, 0, {});
return;
}

auto pages = result->getNumber<uint32_t>("entries");
pages += entriesPerPage - 1;
pages /= entriesPerPage;

std::vector<RecentPvPKillEntry> entries;
entries.reserve(result->countResults());
do {
std::string cause1 = result->getString("killed_by");
std::string cause2 = result->getString("mostdamage_by");
std::ostringstream description;
description << "Died at Level " << result->getNumber<uint32_t>("level") << " by";
if (!cause1.empty()) {
description << getArticle(cause1) << cause1;
}
std::string name = result->getString("name");

if (!cause2.empty()) {
if (!cause1.empty()) {
description << " and";
uint8_t status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_JUSTIFIED;
if (player->getName() == cause1) {
if (result->getNumber<uint32_t>("unjustified") == 1) {
status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_UNJUSTIFIED;
}
} else if (player->getName() == cause2) {
if (result->getNumber<uint32_t>("mostdamage_unjustified") == 1) {
status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_UNJUSTIFIED;
}
description << getArticle(cause2) << cause2;
}
description << '.';

insertDeathOnHistory(std::move(description.str()), result->getNumber<uint32_t>("time"));
entries.emplace_back(fmt::format("Killed {}.", name), result->getNumber<uint32_t>("time"), status);
} while (result->next());
}
player->sendCyclopediaCharacterRecentPvPKills(page, static_cast<uint16_t>(pages), entries);
};
g_databaseTasks().store(query, callback);
m_player.addAsyncOngoingTask(PlayerAsyncTask_RecentPvPKills);

g_logger().debug("Checking and updating death history of player {} took {} milliseconds.", m_player.getName(), bm_check.duration());
g_logger().debug("Loading recent kills from the player {} took {} milliseconds.", m_player.getName(), bm_check.duration());
}

void PlayerCyclopedia::updateStoreSummary(uint8_t type, uint16_t amount, const std::string &id) {
Expand Down Expand Up @@ -118,26 +157,6 @@ void PlayerCyclopedia::updateAmount(uint8_t type, uint16_t amount) {
m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(type))->set("amount", oldAmount + amount);
}

std::vector<RecentDeathEntry> PlayerCyclopedia::getDeathHistory() const {
return m_deathHistory;
}

void PlayerCyclopedia::insertDeathOnHistory(std::string cause, uint32_t timestamp) {
m_deathHistory.emplace_back(std::move(cause), timestamp);
}

std::vector<RecentPvPKillEntry> PlayerCyclopedia::getPvpKillsHistory() const {
return m_pvpKillsHistory;
}

void PlayerCyclopedia::insertPvpKillOnHistory(std::string cause, uint32_t timestamp, uint8_t status) {
m_pvpKillsHistory.emplace_back(std::move(cause), timestamp, status);
}

Summary PlayerCyclopedia::getSummary() {
return { getAmount(Summary_t::BOOSTS), getAmount(Summary_t::PREY_CARDS), getAmount(Summary_t::INSTANT_REWARDS), getAmount(Summary_t::HIRELINGS) };
}

std::map<uint16_t, uint16_t> PlayerCyclopedia::getResult(uint8_t type) const {
auto kvScope = m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(type));
std::map<uint16_t, uint16_t> result; // ID, amount
Expand Down
31 changes: 12 additions & 19 deletions src/creatures/players/cyclopedia/player_cyclopedia.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,42 @@

#pragma once

#include <creatures/creatures_definitions.hpp>
#include <utils/utils_definitions.hpp>
#include <enums/player_cyclopedia.hpp>
#include "creatures/creatures_definitions.hpp"
#include "enums/player_cyclopedia.hpp"

class Player;
class KV;

struct Summary {
uint16_t m_xpBoosts = 0;
uint16_t m_preyWildcards = 0;
uint16_t m_instantRewards = 0;
uint16_t m_hirelings = 0;

Summary(uint16_t mXpBoosts, uint16_t mPreyWildcards, uint16_t mInstantRewards, uint16_t mHirelings) :
m_xpBoosts(mXpBoosts), m_preyWildcards(mPreyWildcards), m_instantRewards(mInstantRewards), m_hirelings(mHirelings) { }
Summary(uint16_t mPreyWildcards, uint16_t mInstantRewards, uint16_t mHirelings) :
m_preyWildcards(mPreyWildcards), m_instantRewards(mInstantRewards), m_hirelings(mHirelings) { }
};

class PlayerCyclopedia {
public:
explicit PlayerCyclopedia(Player &player);

Summary getSummary() {
return { getAmount(Summary_t::PREY_CARDS),
getAmount(Summary_t::INSTANT_REWARDS),
getAmount(Summary_t::HIRELINGS) };
}

void loadSummaryData();
void loadSummary();
void loadRecentKills();
void loadDeathHistory();
void loadDeathHistory(uint16_t page, uint16_t entriesPerPage);
void loadRecentKills(uint16_t page, uint16_t entriesPerPage);

void updateStoreSummary(uint8_t type, uint16_t amount = 1, const std::string &id = "");
uint16_t getAmount(uint8_t type);
void updateAmount(uint8_t type, uint16_t amount = 1);

[[nodiscard]] std::vector<RecentDeathEntry> getDeathHistory() const;
void insertDeathOnHistory(std::string cause, uint32_t timestamp);

[[nodiscard]] std::vector<RecentPvPKillEntry> getPvpKillsHistory() const;
void insertPvpKillOnHistory(std::string cause, uint32_t timestamp, uint8_t status);

Summary getSummary();

[[nodiscard]] std::map<uint16_t, uint16_t> getResult(uint8_t type) const;
void insertValue(uint8_t type, uint16_t amount = 1, const std::string &id = "");

private:
std::vector<RecentDeathEntry> m_deathHistory;
std::vector<RecentPvPKillEntry> m_pvpKillsHistory;
Player &m_player;
};
22 changes: 0 additions & 22 deletions src/creatures/players/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2859,28 +2859,6 @@ void Player::death(std::shared_ptr<Creature> lastHitCreature) {
}
sendTextMessage(MESSAGE_EVENT_ADVANCE, blessOutput.str());

// Pvp and pve death registration
std::ostringstream description;
if (pvpDeath) {
description << "Killed " << getName() << '.';
CyclopediaCharacterInfo_RecentKillStatus_t status = unfairFightReduction != 100 ? CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_UNJUSTIFIED : CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_JUSTIFIED;
if (lastHitCreature && lastHitCreature->getPlayer()) {
lastHitCreature->getPlayer()->cyclopedia()->insertPvpKillOnHistory(std::move(description.str()), OTSYS_TIME() / 1000, status);
} else if (lastHitCreature && lastHitCreature->getMaster() && lastHitCreature->getMaster()->getPlayer()) {
lastHitCreature->getMaster()->getPlayer()->cyclopedia()->insertPvpKillOnHistory(std::move(description.str()), OTSYS_TIME() / 1000, status);
}
} else {
description << "Died at Level " << getLevel() << " by";
if (lastHitCreature) {
description << getArticle(lastHitCreature->getName()) << lastHitCreature->getName();
} else {
description << " a field item";
}
description << '.';

cyclopedia()->insertDeathOnHistory(std::move(description.str()), OTSYS_TIME() / 1000);
}

sendStats();
sendSkills();
sendReLoginWindow(unfairFightReduction);
Expand Down
8 changes: 4 additions & 4 deletions src/creatures/players/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1631,14 +1631,14 @@ class Player final : public Creature, public Cylinder, public Bankable {
client->sendCyclopediaCharacterCombatStats();
}
}
void sendCyclopediaCharacterRecentDeaths(uint16_t page, uint16_t entriesPerPage) {
void sendCyclopediaCharacterRecentDeaths(uint16_t page, uint16_t pages, const std::vector<RecentDeathEntry> &entries) {
if (client) {
client->sendCyclopediaCharacterRecentDeaths(page, entriesPerPage);
client->sendCyclopediaCharacterRecentDeaths(page, pages, entries);
}
}
void sendCyclopediaCharacterRecentPvPKills(uint16_t page, uint16_t entriesPerPage) {
void sendCyclopediaCharacterRecentPvPKills(uint16_t page, uint16_t pages, const std::vector<RecentPvPKillEntry> &entries) {
if (client) {
client->sendCyclopediaCharacterRecentPvPKills(page, entriesPerPage);
client->sendCyclopediaCharacterRecentPvPKills(page, pages, entries);
}
}
void sendCyclopediaCharacterAchievements(uint16_t secretsUnlocked, std::vector<std::pair<Achievement, uint32_t>> achievementsUnlocked);
Expand Down
6 changes: 3 additions & 3 deletions src/game/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8351,10 +8351,10 @@ void Game::playerCyclopediaCharacterInfo(std::shared_ptr<Player> player, uint32_
player->sendCyclopediaCharacterCombatStats();
break;
case CYCLOPEDIA_CHARACTERINFO_RECENTDEATHS:
player->sendCyclopediaCharacterRecentDeaths(page, entriesPerPage);
player->cyclopedia()->loadDeathHistory(page, entriesPerPage);
break;
case CYCLOPEDIA_CHARACTERINFO_RECENTPVPKILLS:
player->sendCyclopediaCharacterRecentPvPKills(page, entriesPerPage);
player->cyclopedia()->loadRecentKills(page, entriesPerPage);
break;
case CYCLOPEDIA_CHARACTERINFO_ACHIEVEMENTS:
player->achiev()->sendUnlockedSecretAchievements();
Expand Down Expand Up @@ -10677,7 +10677,7 @@ Title Game::getTitleByName(const std::string &name) {
return {};
}

std::unordered_map<uint8_t, std::string> Game::getBlessingNames() {
std::map<uint8_t, std::string> Game::getBlessingNames() {
return m_blessingNames;
}

Expand Down
4 changes: 2 additions & 2 deletions src/game/game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ class Game {
return m_summaryCategories[type];
}

std::unordered_map<uint8_t, std::string> getBlessingNames();
std::map<uint8_t, std::string> getBlessingNames();
std::unordered_map<uint16_t, std::string> getHirelingSkills();
std::unordered_map<uint16_t, std::string> getHirelingOutfits();

Expand All @@ -749,7 +749,7 @@ class Game {
std::vector<HighscoreCategory> m_highscoreCategories;
std::unordered_map<uint8_t, std::string> m_highscoreCategoriesNames;

std::unordered_map<uint8_t, std::string> m_blessingNames;
std::map<uint8_t, std::string> m_blessingNames;

std::unordered_map<uint8_t, std::string> m_summaryCategories;
std::unordered_map<uint16_t, std::string> m_hirelingSkills;
Expand Down
Loading

0 comments on commit 216f870

Please sign in to comment.