[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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 241 additions and 270 deletions

View File

@ -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)

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("");
}

View File

@ -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 <vector>
#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<TitlesRepository::Titles> 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<TitleEntry>& 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<TitlesRepository::Titles>& GetTitles() { return titles; }
protected:
std::vector<TitleEntry> titles;
std::vector<TitlesRepository::Titles> titles;
};
extern TitleManager title_manager;