[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
This commit is contained in:
Alex King
2025-02-07 00:25:36 -05:00
committed by GitHub
parent 1a48add20e
commit 537b585791
3 changed files with 241 additions and 270 deletions
+227 -223
View File
@@ -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<TitleEntry> 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<TitlesRepository::Titles> TitleManager::GetEligibleTitles(Client* c)
{
std::vector<TitlesRepository::Titles> 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<uint32>(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<uint32>(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<EQ::skills::SkillType>(title.skill_id);
if (title.min_skill_value >= 0 && client->GetRawSkill(skill_id) < static_cast<uint32>(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<uint32>(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<EQ::skills::SkillType>(t.skill_id);
if (
t.min_skill_value >= 0 &&
c->GetRawSkill(skill_id) < static_cast<uint32>(t.min_skill_value)
) {
continue;
}
if (
t.max_skill_value >= 0 &&
c->GetRawSkill(skill_id) > static_cast<uint32>(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("");
}