From 537b5857911d3c9e693b2a52037b9717bd880ce4 Mon Sep 17 00:00:00 2001 From: Alex King <89047260+Kinglykrab@users.noreply.github.com> Date: Fri, 7 Feb 2025 00:25:36 -0500 Subject: [PATCH] [Cleanup] Use Repositories for Titles (#4608) * [Cleanup] Use Repositories for Titles * Update titles.h * Further use repositories * Revert "Further use repositories" This reverts commit 80d5f750f0157657af05497eeade8b45e15dc12a. * Push * Update titles.cpp * Push * Merge branch 'cleanup/titles_repositories' of https://github.com/EQEmu/Server into cleanup/titles_repositories * Final push --- zone/client_packet.cpp | 5 +- zone/titles.cpp | 450 +++++++++++++++++++++-------------------- zone/titles.h | 56 +---- 3 files changed, 241 insertions(+), 270 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 3f5a6e49f..4032522e5 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -13489,10 +13489,11 @@ void Client::Handle_OP_RequestDuel(const EQApplicationPacket *app) void Client::Handle_OP_RequestTitles(const EQApplicationPacket *app) { - EQApplicationPacket *outapp = title_manager.MakeTitlesPacket(this); + auto outapp = title_manager.MakeTitlesPacket(this); - if (outapp != nullptr) + if (outapp) { FastQueuePacket(&outapp); + } } void Client::Handle_OP_RespawnWindow(const EQApplicationPacket *app) diff --git a/zone/titles.cpp b/zone/titles.cpp index 0f30bd27b..ae078600a 100644 --- a/zone/titles.cpp +++ b/zone/titles.cpp @@ -1,28 +1,9 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2005 EQEMu Development Team (http://eqemulator.net) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - #include "../common/eq_packet_structs.h" #include "../common/strings.h" #include "../common/misc_functions.h" #include "../common/repositories/player_titlesets_repository.h" #include "client.h" -#include "entity.h" #include "mob.h" #include "titles.h" @@ -37,209 +18,228 @@ bool TitleManager::LoadTitles() { titles.clear(); - std::string query = "SELECT `id`, `skill_id`, `min_skill_value`, `max_skill_value`, " - "`min_aa_points`, `max_aa_points`, `class`, `gender`, `char_id`, " - "`status`, `item_id`, `prefix`, `suffix`, `title_set` FROM titles"; - auto results = database.QueryDatabase(query); - if (!results.Success() || !results.RowCount()) { + const auto& l = TitlesRepository::All(database); + + if (l.empty()) { return false; } - for (auto row : results) { - TitleEntry title; - title.title_id = Strings::ToInt(row[0]); - title.skill_id = (EQ::skills::SkillType) Strings::ToInt(row[1]); - title.min_skill_value = Strings::ToInt(row[2]); - title.max_skill_value = Strings::ToInt(row[3]); - title.min_aa_points = Strings::ToInt(row[4]); - title.max_aa_points = Strings::ToInt(row[5]); - title.class_id = Strings::ToInt(row[6]); - title.gender_id = Strings::ToInt(row[7]); - title.character_id = Strings::ToInt(row[8]); - title.status = Strings::ToInt(row[9]); - title.item_id = Strings::ToInt(row[10]); - title.prefix = row[11]; - title.suffix = row[12]; - title.titleset = Strings::ToInt(row[13]); - titles.push_back(title); + for (const auto& e : l) { + titles.push_back(e); } - LogInfo("Loaded [{}] titles", Strings::Commify(std::to_string(results.RowCount()))); + LogInfo("Loaded [{}] Title{}", Strings::Commify(l.size()), l.size() != 1 ? "s" : ""); return true; } -EQApplicationPacket *TitleManager::MakeTitlesPacket(Client *client) +EQApplicationPacket* TitleManager::MakeTitlesPacket(Client* c) { - std::vector available_titles; - uint32 length = 4; - for (const auto& title : titles) { - if (!IsClientEligibleForTitle(client, title)) { + const auto& eligible_titles = GetEligibleTitles(c); + + uint32 total_length = 4; + + for (const auto& e : eligible_titles) { + total_length += e.prefix.length() + e.suffix.length() + 6; + } + + auto outapp = new EQApplicationPacket(OP_SendTitleList, total_length); + char* buffer = (char*) outapp->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, buffer, eligible_titles.size()); + + for (const auto& t : eligible_titles) { + VARSTRUCT_ENCODE_TYPE(uint32, buffer, t.id); + VARSTRUCT_ENCODE_STRING(buffer, t.prefix.c_str()); + VARSTRUCT_ENCODE_STRING(buffer, t.suffix.c_str()); + } + + return outapp; +} + +std::string TitleManager::GetPrefix(int title_set) +{ + if (!title_set) { + return ""; + } + + auto e = std::find_if( + titles.begin(), + titles.end(), + [title_set](const auto& t) { + return t.title_set == title_set; + } + ); + + return e != titles.end() ? e->prefix : ""; +} + +std::string TitleManager::GetSuffix(int title_set) +{ + if (!title_set) { + return ""; + } + + auto e = std::find_if( + titles.begin(), + titles.end(), + [title_set](const auto& t) { + return t.title_set == title_set; + } + ); + + return e != titles.end() ? e->suffix : ""; +} + +bool TitleManager::HasTitle(Client* c, uint32 title_id) +{ + if (!c || !title_id) { + return false; + } + + const auto& eligible_titles = GetEligibleTitles(c); + + return std::any_of( + eligible_titles.begin(), + eligible_titles.end(), + [title_id](const auto& t) { + return t.id == title_id; + } + ); +} + +std::vector TitleManager::GetEligibleTitles(Client* c) +{ + std::vector eligible_titles = {}; + if (!c) { + return eligible_titles; + } + + const auto& player_title_sets = PlayerTitlesetsRepository::GetWhere( + database, + fmt::format( + "`char_id` = {}", + c->CharacterID() + ) + ); + + for (auto t : titles) { + if (t.char_id >= 0 && c->CharacterID() != static_cast(t.char_id)) { continue; } - available_titles.push_back(title); - length += title.prefix.length() + title.suffix.length() + 6; - } - - auto outapp = new EQApplicationPacket(OP_SendTitleList, length); - char *buffer = (char *)outapp->pBuffer; - VARSTRUCT_ENCODE_TYPE(uint32, buffer, available_titles.size()); - for (const auto& available_title : available_titles) { - VARSTRUCT_ENCODE_TYPE(uint32, buffer, available_title.title_id); - VARSTRUCT_ENCODE_STRING(buffer, available_title.prefix.c_str()); - VARSTRUCT_ENCODE_STRING(buffer, available_title.suffix.c_str()); - } - return(outapp); -} - -std::string TitleManager::GetPrefix(int title_id) -{ - if (!title_id) { - return ""; - } - - for (const auto& title : titles) { - if (title.title_id == title_id) { - return title.prefix; - } - } - - return ""; -} - -std::string TitleManager::GetSuffix(int title_id) -{ - if (!title_id) { - return ""; - } - - for (const auto& title : titles) { - if (title.title_id == title_id) { - return title.suffix; - } - } - - return ""; -} - -bool TitleManager::HasTitle(Client* client, uint32 title_id) -{ - if (!client || !title_id) { - return false; - } - - for (const auto& title : titles) { - if (title.title_id == title_id) { - return IsClientEligibleForTitle(client, title); - } - } - - return false; -} - -bool TitleManager::IsClientEligibleForTitle(Client *client, TitleEntry title) -{ - if (!client) { - return false; - } - - if (title.character_id >= 0 && client->CharacterID() != static_cast(title.character_id)) { - return false; - } - - if (title.status >= 0 && client->Admin() < title.status) { - return false; - } - - if (title.gender_id >= Gender::Male && client->GetBaseGender() != title.gender_id) { - return false; - } - - if (title.class_id >= Class::None && client->GetBaseClass() != title.class_id) { - return false; - } - - if (title.min_aa_points >= 0 && client->GetSpentAA() < title.min_aa_points) { - return false; - } - - if (title.max_aa_points >= 0 && client->GetSpentAA() > title.max_aa_points) { - return false; - } - - if (title.skill_id >= 0) { - auto skill_id = static_cast(title.skill_id); - if (title.min_skill_value >= 0 && client->GetRawSkill(skill_id) < static_cast(title.min_skill_value)) { - return false; + if (t.status >= 0 && c->Admin() < t.status) { + continue; } - if (title.max_skill_value >= 0 && client->GetRawSkill(skill_id) > static_cast(title.max_skill_value)) { - return false; + if (t.gender >= Gender::Male && c->GetBaseGender() != t.gender) { + continue; } + + if (t.class_ >= Class::None && c->GetBaseClass() != t.class_) { + continue; + } + + if (t.min_aa_points >= 0 && c->GetSpentAA() < t.min_aa_points) { + continue; + } + + if (t.max_aa_points >= 0 && c->GetSpentAA() > t.max_aa_points) { + continue; + } + + if (t.skill_id >= 0) { + auto skill_id = static_cast(t.skill_id); + if ( + t.min_skill_value >= 0 && + c->GetRawSkill(skill_id) < static_cast(t.min_skill_value) + ) { + continue; + } + + if ( + t.max_skill_value >= 0 && + c->GetRawSkill(skill_id) > static_cast(t.max_skill_value) + ) { + continue; + } + } + + if (t.item_id >= 1 && c->GetInv().HasItem(t.item_id) == INVALID_INDEX) { + continue; + } + + if ( + t.title_set > 0 && + !std::any_of( + player_title_sets.begin(), + player_title_sets.end(), + [t](const auto& e) { + return e.title_set == t.title_set; + } + ) + ) { + continue; + } + + eligible_titles.emplace_back(t); } - if (title.item_id >= 1 && client->GetInv().HasItem(title.item_id) == INVALID_INDEX) { - return false; - } - - if (title.titleset > 0 && !client->CheckTitle(title.titleset)) { - return false; - } - - return true; + return eligible_titles; } bool TitleManager::IsNewAATitleAvailable(int aa_points, int class_id) { - for (const auto& title : titles) { - if ( - (title.class_id == -1 || title.class_id == class_id) && - title.min_aa_points == aa_points - ) { - return true; + return std::any_of( + titles.begin(), + titles.end(), + [class_id, aa_points](const auto& t) { + return ( + (t.class_ == -1 || t.class_ == class_id) && + t.min_aa_points == aa_points + ); } - } - - return false; + ); } bool TitleManager::IsNewTradeSkillTitleAvailable(int skill_id, int skill_value) { - for (const auto& title : titles) { - if (title.skill_id == skill_id && title.min_skill_value == skill_value) { - return true; + return std::any_of( + titles.begin(), + titles.end(), + [skill_id, skill_value](const auto& t) { + return t.skill_id == skill_id && t.min_skill_value == skill_value; } - } - - return false; + ); } -void TitleManager::CreateNewPlayerTitle(Client *client, std::string title) +void TitleManager::CreateNewPlayerTitle(Client* c, std::string title) { - if (!client || title.empty()) { + if (!c || title.empty()) { return; } - client->SetAATitle(title); + c->SetAATitle(title); - auto query = fmt::format( - "SELECT `id` FROM titles WHERE `prefix` = '{}' AND char_id = {}", - Strings::Escape(title), - client->CharacterID() + const auto& l = TitlesRepository::GetWhere( + database, + fmt::format( + "`char_id` = {} AND `prefix` = '{}'", + c->CharacterID(), + Strings::Escape(title) + ) ); - auto results = database.QueryDatabase(query); - if (results.Success() && results.RowCount()){ + + if (!l.empty()) { return; } - query = fmt::format( - "INSERT INTO titles (`char_id`, `prefix`) VALUES ({}, '{}')", - client->CharacterID(), - Strings::Escape(title) - ); - results = database.QueryDatabase(query); - if (!results.Success()) { + auto e = TitlesRepository::NewEntity(); + + e.char_id = c->CharacterID(); + e.prefix = title; + + if (!TitlesRepository::InsertOne(database, e).id) { return; } @@ -248,31 +248,33 @@ void TitleManager::CreateNewPlayerTitle(Client *client, std::string title) safe_delete(pack); } -void TitleManager::CreateNewPlayerSuffix(Client *client, std::string suffix) +void TitleManager::CreateNewPlayerSuffix(Client* c, std::string suffix) { - if (!client || suffix.empty()) { + if (!c || suffix.empty()) { return; } - client->SetTitleSuffix(suffix); + c->SetTitleSuffix(suffix); - auto query = fmt::format( - "SELECT `id` FROM titles WHERE `suffix` = '{}' AND char_id = {}", - Strings::Escape(suffix), - client->CharacterID() + const auto& l = TitlesRepository::GetWhere( + database, + fmt::format( + "`char_id` = {} AND `suffix` = '{}'", + c->CharacterID(), + Strings::Escape(suffix) + ) ); - auto results = database.QueryDatabase(query); - if (results.Success() && results.RowCount()) { + + if (!l.empty()) { return; } - query = fmt::format( - "INSERT INTO titles (`char_id`, `suffix`) VALUES ({}, '{}')", - client->CharacterID(), - Strings::Escape(suffix) - ); - results = database.QueryDatabase(query); - if (!results.Success()) { + auto e = TitlesRepository::NewEntity(); + + e.char_id = c->CharacterID(); + e.suffix = suffix; + + if (!TitlesRepository::InsertOne(database, e).id) { return; } @@ -284,10 +286,13 @@ void TitleManager::CreateNewPlayerSuffix(Client *client, std::string suffix) void Client::SetAATitle(std::string title) { strn0cpy(m_pp.title, title.c_str(), sizeof(m_pp.title)); + auto outapp = new EQApplicationPacket(OP_SetTitleReply, sizeof(SetTitleReply_Struct)); - auto strs = (SetTitleReply_Struct *) outapp->pBuffer; + auto strs = (SetTitleReply_Struct*) outapp->pBuffer; + strn0cpy(strs->title, title.c_str(), sizeof(strs->title)); strs->entity_id = GetID(); + entity_list.QueueClients(this, outapp, false); safe_delete(outapp); } @@ -295,11 +300,14 @@ void Client::SetAATitle(std::string title) void Client::SetTitleSuffix(std::string suffix) { strn0cpy(m_pp.suffix, suffix.c_str(), sizeof(m_pp.suffix)); + auto outapp = new EQApplicationPacket(OP_SetTitleReply, sizeof(SetTitleReply_Struct)); - auto strs = (SetTitleReply_Struct *) outapp->pBuffer; + auto strs = (SetTitleReply_Struct*) outapp->pBuffer; + strs->is_suffix = 1; strn0cpy(strs->title, suffix.c_str(), sizeof(strs->title)); strs->entity_id = GetID(); + entity_list.QueueClients(this, outapp, false); safe_delete(outapp); } @@ -310,13 +318,12 @@ void Client::EnableTitle(int title_set) return; } - std::string query = fmt::format( - "INSERT INTO player_titlesets (char_id, title_set) VALUES ({}, {})", - CharacterID(), - title_set - ); - auto results = database.QueryDatabase(query); - if (!results.Success()) { + auto e = PlayerTitlesetsRepository::NewEntity(); + + e.char_id = CharacterID(); + e.title_set = title_set; + + if (!PlayerTitlesetsRepository::InsertOne(database, e).id) { LogError("Error in EnableTitle query for titleset [{}] and charid [{}]", title_set, CharacterID()); } @@ -324,17 +331,14 @@ void Client::EnableTitle(int title_set) bool Client::CheckTitle(int title_set) { - std::string query = fmt::format( - "SELECT `id` FROM player_titlesets WHERE `title_set` = {} AND `char_id` = {} LIMIT 1", - title_set, - CharacterID() - ); - auto results = database.QueryDatabase(query); - if (!results.Success() || !results.RowCount()) { - return false; - } - - return true; + return !PlayerTitlesetsRepository::GetWhere( + database, + fmt::format( + "`char_id` = {} AND `title_set` = {}", + CharacterID(), + title_set + ) + ).empty(); } void Client::RemoveTitle(int title_set) @@ -343,13 +347,13 @@ void Client::RemoveTitle(int title_set) return; } - for (const auto& title : title_manager.GetTitles()) { - if (title.titleset == title_set) { - if (std::string(m_pp.title) == title.prefix) { + for (const auto& t : title_manager.GetTitles()) { + if (t.title_set == title_set) { + if (std::string(m_pp.title) == t.prefix) { SetAATitle(""); } - if (std::string(m_pp.suffix) == title.suffix) { + if (std::string(m_pp.suffix) == t.suffix) { SetTitleSuffix(""); } diff --git a/zone/titles.h b/zone/titles.h index 32909cb3f..0edfc5a67 100644 --- a/zone/titles.h +++ b/zone/titles.h @@ -1,46 +1,12 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2005 EQEMu Development Team (http://eqemulator.net) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ #ifndef TITLES_H #define TITLES_H #include +#include "../common/repositories/titles_repository.h" class Client; class EQApplicationPacket; -struct TitleEntry -{ - int title_id; - int skill_id; - int min_skill_value; - int max_skill_value; - int min_aa_points; - int max_aa_points; - int class_id; - int gender_id; - int character_id; - int status; - int item_id; - std::string prefix; - std::string suffix; - int titleset; -}; - class TitleManager { public: @@ -48,19 +14,19 @@ public: bool LoadTitles(); - EQApplicationPacket *MakeTitlesPacket(Client *client); - std::string GetPrefix(int title_id); - std::string GetSuffix(int title_id); - bool IsClientEligibleForTitle(Client *client, TitleEntry title); + EQApplicationPacket* MakeTitlesPacket(Client* c); + std::string GetPrefix(int title_set); + std::string GetSuffix(int title_set); + std::vector GetEligibleTitles(Client* c); bool IsNewAATitleAvailable(int aa_points, int class_id); - bool IsNewTradeSkillTitleAvailable(int skill_id, int skill_value); - void CreateNewPlayerTitle(Client *client, std::string title); - void CreateNewPlayerSuffix(Client *client, std::string suffix); - bool HasTitle(Client* client, uint32 title_id); - inline const std::vector& GetTitles() { return titles; } + bool IsNewTradeSkillTitleAvailable(int t, int skill_value); + void CreateNewPlayerTitle(Client* c, std::string title); + void CreateNewPlayerSuffix(Client* c, std::string suffix); + bool HasTitle(Client* c, uint32 title_id); + inline const std::vector& GetTitles() { return titles; } protected: - std::vector titles; + std::vector titles; }; extern TitleManager title_manager;