From dadc1b28436abcdee3ffaaa897b344fd64227263 Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Wed, 7 Apr 2021 02:20:35 -0400 Subject: [PATCH] [Expeditions] Refactor expedition caching (#1315) Add common expedition base class Use repository for zone and world expedition caching World now stores members and leader as Member objects instead of ids This improves readability of the caching methods and lets world cache expedition dzs and members like zone. World also now caches expeditions as unique_ptr which will be necessary for future dz callback lambdas that capture 'this' so addresses don't change on cache vector resizes. --- common/CMakeLists.txt | 2 + common/eq_constants.h | 9 + common/expedition_base.cpp | 93 +++++++ common/expedition_base.h | 74 ++++++ .../base_expedition_lockouts_repository.h | 2 +- .../expedition_lockouts_repository.h | 52 ++++ .../expedition_members_repository.h | 62 +++++ common/repositories/expeditions_repository.h | 94 +++++++ world/dynamic_zone.cpp | 15 -- world/dynamic_zone.h | 4 - world/expedition.cpp | 58 ++--- world/expedition.h | 21 +- world/expedition_database.cpp | 84 ------- world/expedition_database.h | 2 - world/expedition_message.cpp | 10 +- world/expedition_state.cpp | 107 +++++--- world/expedition_state.h | 12 +- world/main.cpp | 2 +- zone/command.cpp | 6 +- zone/dynamic_zone.cpp | 16 -- zone/dynamic_zone.h | 2 - zone/expedition.cpp | 229 +++++------------- zone/expedition.h | 59 +---- zone/expedition_database.cpp | 94 ------- zone/expedition_database.h | 24 -- zone/lua_expedition.cpp | 2 +- zone/perl_expedition.cpp | 4 +- 27 files changed, 580 insertions(+), 559 deletions(-) create mode 100644 common/expedition_base.cpp create mode 100644 common/expedition_base.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index bb932490c..08db08585 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -32,6 +32,7 @@ SET(common_sources eq_stream_proxy.cpp eqtime.cpp event_sub.cpp + expedition_base.cpp expedition_lockout_timer.cpp extprofile.cpp faction.cpp @@ -495,6 +496,7 @@ SET(common_headers eqtime.h errmsg.h event_sub.h + expedition_base.h expedition_lockout_timer.h extprofile.h faction.h diff --git a/common/eq_constants.h b/common/eq_constants.h index cb042043f..b17dcc2be 100644 --- a/common/eq_constants.h +++ b/common/eq_constants.h @@ -474,4 +474,13 @@ enum class DynamicZoneType Quest }; +enum class ExpeditionMemberStatus : uint8_t +{ + Unknown = 0, + Online, + Offline, + InDynamicZone, + LinkDead +}; + #endif /*COMMON_EQ_CONSTANTS_H*/ diff --git a/common/expedition_base.cpp b/common/expedition_base.cpp new file mode 100644 index 000000000..fa4962706 --- /dev/null +++ b/common/expedition_base.cpp @@ -0,0 +1,93 @@ +#include "expedition_base.h" +#include "repositories/expeditions_repository.h" + +ExpeditionBase::ExpeditionBase(uint32_t id, const std::string& uuid, + const std::string& expedition_name, const ExpeditionMember& leader, + uint32_t min_players, uint32_t max_players +) : + m_id(id), + m_uuid(uuid), + m_expedition_name(expedition_name), + m_leader(leader), + m_min_players(min_players), + m_max_players(max_players) +{ +} + +void ExpeditionBase::LoadRepositoryResult(ExpeditionsRepository::ExpeditionWithLeader&& entry) +{ + m_id = entry.id; + m_uuid = std::move(entry.uuid); + m_expedition_name = std::move(entry.expedition_name); + m_min_players = entry.min_players; + m_max_players = entry.max_players; + m_add_replay_on_join = entry.add_replay_on_join; + m_is_locked = entry.is_locked; + m_leader.char_id = entry.leader_id; + m_leader.name = std::move(entry.leader_name); +} + +void ExpeditionBase::AddMemberFromRepositoryResult( + ExpeditionMembersRepository::MemberWithName&& entry) +{ + auto status = ExpeditionMemberStatus::Unknown; + AddInternalMember({ entry.character_id, std::move(entry.character_name), status }); +} + +void ExpeditionBase::AddInternalMember(const ExpeditionMember& member) +{ + if (!HasMember(member.char_id)) + { + m_members.emplace_back(member); + } +} + +void ExpeditionBase::RemoveInternalMember(uint32_t character_id) +{ + m_members.erase(std::remove_if(m_members.begin(), m_members.end(), + [&](const ExpeditionMember& member) { return member.char_id == character_id; } + ), m_members.end()); +} + + +bool ExpeditionBase::HasMember(uint32_t character_id) +{ + return std::any_of(m_members.begin(), m_members.end(), [&](const ExpeditionMember& member) { + return member.char_id == character_id; + }); +} + +bool ExpeditionBase::HasMember(const std::string& character_name) +{ + return std::any_of(m_members.begin(), m_members.end(), [&](const ExpeditionMember& member) { + return (strcasecmp(member.name.c_str(), character_name.c_str()) == 0); + }); +} + +ExpeditionMember ExpeditionBase::GetMemberData(uint32_t character_id) +{ + auto it = std::find_if(m_members.begin(), m_members.end(), [&](const ExpeditionMember& member) { + return member.char_id == character_id; + }); + + ExpeditionMember member_data; + if (it != m_members.end()) + { + member_data = *it; + } + return member_data; +} + +ExpeditionMember ExpeditionBase::GetMemberData(const std::string& character_name) +{ + auto it = std::find_if(m_members.begin(), m_members.end(), [&](const ExpeditionMember& member) { + return (strcasecmp(member.name.c_str(), character_name.c_str()) == 0); + }); + + ExpeditionMember member_data; + if (it != m_members.end()) + { + member_data = *it; + } + return member_data; +} diff --git a/common/expedition_base.h b/common/expedition_base.h new file mode 100644 index 000000000..aeb072fae --- /dev/null +++ b/common/expedition_base.h @@ -0,0 +1,74 @@ +#ifndef COMMON_EXPEDITION_BASE_H +#define COMMON_EXPEDITION_BASE_H + +#include "eq_constants.h" +#include "repositories/expeditions_repository.h" +#include "repositories/expedition_members_repository.h" +#include +#include +#include + +struct ExpeditionMember +{ + uint32_t char_id = 0; + std::string name; + ExpeditionMemberStatus status = ExpeditionMemberStatus::Online; + + ExpeditionMember() = default; + ExpeditionMember(uint32_t id, const std::string& name_) + : char_id(id), name(name_) {} + ExpeditionMember(uint32_t id, const std::string& name_, ExpeditionMemberStatus status_) + : char_id(id), name(name_), status(status_) {} + + bool IsValid() const { return char_id != 0 && !name.empty(); } +}; + +class ExpeditionBase +{ +public: + virtual ~ExpeditionBase() = default; + ExpeditionBase(const ExpeditionBase&) = default; + ExpeditionBase(ExpeditionBase&&) = default; + ExpeditionBase& operator=(const ExpeditionBase&) = default; + ExpeditionBase& operator=(ExpeditionBase&&) = default; + + uint32_t GetID() const { return m_id; } + uint32_t GetLeaderID() const { return m_leader.char_id; } + uint32_t GetMinPlayers() const { return m_min_players; } + uint32_t GetMaxPlayers() const { return m_max_players; } + uint32_t GetMemberCount() const { return static_cast(m_members.size()); } + const std::string& GetName() const { return m_expedition_name; } + const std::string& GetLeaderName() const { return m_leader.name; } + const std::string& GetUUID() const { return m_uuid; } + const std::vector& GetMembers() const { return m_members; } + + void AddInternalMember(const ExpeditionMember& member); + void ClearInternalMembers() { m_members.clear(); } + bool HasMember(const std::string& character_name); + bool HasMember(uint32_t character_id); + bool IsEmpty() const { return m_members.empty(); } + void RemoveInternalMember(uint32_t character_id); + + void LoadRepositoryResult(ExpeditionsRepository::ExpeditionWithLeader&& entry); + void AddMemberFromRepositoryResult(ExpeditionMembersRepository::MemberWithName&& entry); + +protected: + ExpeditionBase() = default; + ExpeditionBase(uint32_t id, const std::string& uuid, const std::string& expedition_name, + const ExpeditionMember& leader, uint32_t min_players, uint32_t max_players); + + ExpeditionMember GetMemberData(uint32_t character_id); + ExpeditionMember GetMemberData(const std::string& character_name); + + uint32_t m_id = 0; + uint32_t m_min_players = 0; + uint32_t m_max_players = 0; + bool m_is_locked = false; + bool m_add_replay_on_join = true; + std::string m_uuid; + std::string m_expedition_name; + ExpeditionMember m_leader; + std::vector m_members; +}; + +#endif diff --git a/common/repositories/base/base_expedition_lockouts_repository.h b/common/repositories/base/base_expedition_lockouts_repository.h index f2f2bd5be..e9c5ceda2 100644 --- a/common/repositories/base/base_expedition_lockouts_repository.h +++ b/common/repositories/base/base_expedition_lockouts_repository.h @@ -78,7 +78,7 @@ public: entry.id = 0; entry.expedition_id = 0; entry.event_name = ""; - entry.expire_time = current_timestamp(); + entry.expire_time = ""; entry.duration = 0; entry.from_expedition_uuid = ""; diff --git a/common/repositories/expedition_lockouts_repository.h b/common/repositories/expedition_lockouts_repository.h index 0f33c4209..5eab18915 100644 --- a/common/repositories/expedition_lockouts_repository.h +++ b/common/repositories/expedition_lockouts_repository.h @@ -65,6 +65,58 @@ public: // Custom extended repository methods here + struct ExpeditionLockoutsWithTimestamp { + uint32_t id; + uint32_t expedition_id; + std::string event_name; + time_t expire_time; + int duration; + std::string from_expedition_uuid; + }; + + static std::vector GetWithTimestamp( + Database& db, const std::vector& expedition_ids) + { + if (expedition_ids.empty()) + { + return {}; + } + + std::vector all_entries; + + auto results = db.QueryDatabase(fmt::format(SQL( + SELECT + id, + expedition_id, + event_name, + UNIX_TIMESTAMP(expire_time), + duration, + from_expedition_uuid + FROM expedition_lockouts + WHERE expedition_id IN ({}) + ), + fmt::join(expedition_ids, ",") + )); + + all_entries.reserve(results.RowCount()); + + for (auto row = results.begin(); row != results.end(); ++row) + { + ExpeditionLockoutsWithTimestamp entry{}; + + int col = 0; + entry.id = strtoul(row[col++], nullptr, 10); + entry.expedition_id = strtoul(row[col++], nullptr, 10); + entry.event_name = row[col++]; + entry.expire_time = strtoull(row[col++], nullptr, 10); + entry.duration = strtol(row[col++], nullptr, 10); + entry.from_expedition_uuid = row[col++]; + + all_entries.emplace_back(std::move(entry)); + } + + return all_entries; + } }; #endif //EQEMU_EXPEDITION_LOCKOUTS_REPOSITORY_H diff --git a/common/repositories/expedition_members_repository.h b/common/repositories/expedition_members_repository.h index 87304a99b..55b5bddd7 100644 --- a/common/repositories/expedition_members_repository.h +++ b/common/repositories/expedition_members_repository.h @@ -65,6 +65,68 @@ public: // Custom extended repository methods here + struct MemberWithName { + uint32_t id; + uint32_t expedition_id; + uint32_t character_id; + int is_current_member; + std::string character_name; + }; + + static std::string SelectMembersWithNames() + { + return std::string(SQL( + SELECT + expedition_members.id, + expedition_members.expedition_id, + expedition_members.character_id, + expedition_members.is_current_member, + character_data.name + FROM expedition_members + INNER JOIN character_data ON expedition_members.character_id = character_data.id + )); + } + + static std::vector GetWithNames(Database& db, + const std::vector& expedition_ids) + { + if (expedition_ids.empty()) + { + return {}; + } + + std::vector all_entries; + + auto results = db.QueryDatabase(fmt::format(SQL( + {} + WHERE expedition_members.expedition_id IN ({}) + AND expedition_members.is_current_member = TRUE; + ), + SelectMembersWithNames(), + fmt::join(expedition_ids, ",") + )); + + if (results.Success()) + { + all_entries.reserve(results.RowCount()); + + for (auto row = results.begin(); row != results.end(); ++row) + { + MemberWithName entry{}; + + int col = 0; + entry.id = strtoul(row[col++], nullptr, 10); + entry.expedition_id = strtoul(row[col++], nullptr, 10); + entry.character_id = strtoul(row[col++], nullptr, 10); + entry.is_current_member = strtoul(row[col++], nullptr, 10); + entry.character_name = row[col++]; + + all_entries.emplace_back(std::move(entry)); + } + } + + return all_entries; + } }; #endif //EQEMU_EXPEDITION_MEMBERS_REPOSITORY_H diff --git a/common/repositories/expeditions_repository.h b/common/repositories/expeditions_repository.h index 3cd2f2352..47c821060 100644 --- a/common/repositories/expeditions_repository.h +++ b/common/repositories/expeditions_repository.h @@ -65,6 +65,100 @@ public: // Custom extended repository methods here + struct ExpeditionWithLeader + { + uint32_t id; + std::string uuid; + uint32_t dynamic_zone_id; + std::string expedition_name; + uint32_t min_players; + uint32_t max_players; + int add_replay_on_join; + int is_locked; + uint32_t leader_id; + std::string leader_name; + }; + + static std::string SelectExpeditionsJoinLeader() + { + return std::string(SQL( + SELECT + expeditions.id, + expeditions.uuid, + expeditions.dynamic_zone_id, + expeditions.expedition_name, + expeditions.min_players, + expeditions.max_players, + expeditions.add_replay_on_join, + expeditions.is_locked, + expeditions.leader_id, + character_data.name leader_name + FROM expeditions + INNER JOIN character_data ON expeditions.leader_id = character_data.id + )); + } + + static ExpeditionWithLeader FillExpeditionWithLeaderFromRow(MySQLRequestRow& row) + { + ExpeditionWithLeader entry{}; + + int col = 0; + entry.id = strtoul(row[col++], nullptr, 10); + entry.uuid = row[col++]; + entry.dynamic_zone_id = strtoul(row[col++], nullptr, 10); + entry.expedition_name = row[col++]; + entry.min_players = strtoul(row[col++], nullptr, 10); + entry.max_players = strtoul(row[col++], nullptr, 10); + entry.add_replay_on_join = strtoul(row[col++], nullptr, 10); + entry.is_locked = strtoul(row[col++], nullptr, 10); + entry.leader_id = strtoul(row[col++], nullptr, 10); + entry.leader_name = row[col++]; + + return entry; + } + + static std::vector GetAllWithLeaderName(Database& db) + { + std::vector all_entries; + + auto results = db.QueryDatabase(fmt::format( + "{} ORDER BY expeditions.id;", + SelectExpeditionsJoinLeader() + )); + + if (results.Success()) + { + all_entries.reserve(results.RowCount()); + + for (auto row = results.begin(); row != results.end(); ++row) + { + ExpeditionWithLeader entry = FillExpeditionWithLeaderFromRow(row); + all_entries.emplace_back(std::move(entry)); + } + } + + return all_entries; + } + + static ExpeditionWithLeader GetWithLeaderName(Database& db, uint32_t expedition_id) + { + ExpeditionWithLeader entry{}; + + auto results = db.QueryDatabase(fmt::format( + "{} WHERE expeditions.id = {};", + SelectExpeditionsJoinLeader(), + expedition_id + )); + + if (results.Success() && results.RowCount() > 0) + { + auto row = results.begin(); + entry = FillExpeditionWithLeaderFromRow(row); + } + + return entry; + } + struct CharacterExpedition { uint32_t id; diff --git a/world/dynamic_zone.cpp b/world/dynamic_zone.cpp index a845c5b1c..dad35db82 100644 --- a/world/dynamic_zone.cpp +++ b/world/dynamic_zone.cpp @@ -9,21 +9,6 @@ extern ZSList zoneserver_list; -DynamicZone::DynamicZone( - uint32_t id, uint32_t zone_id, uint32_t instance_id, uint32_t zone_version, - uint32_t start_time, uint32_t duration, DynamicZoneType type -) -{ - m_id = id; - m_instance_id = instance_id; - m_zone_id = zone_id; - m_zone_version = zone_version; - m_start_time = std::chrono::system_clock::from_time_t(start_time); - m_duration = std::chrono::seconds(duration); - m_type = type; - m_expire_time = m_start_time + m_duration; -} - Database& DynamicZone::GetDatabase() { return database; diff --git a/world/dynamic_zone.h b/world/dynamic_zone.h index a82ff9d0e..60eb5b65a 100644 --- a/world/dynamic_zone.h +++ b/world/dynamic_zone.h @@ -19,10 +19,6 @@ class DynamicZone : public DynamicZoneBase public: using DynamicZoneBase::DynamicZoneBase; // inherit base constructors - DynamicZone() = default; - DynamicZone(uint32_t id, uint32_t zone_id, uint32_t instance_id, uint32_t zone_version, - uint32_t start_time, uint32_t duration, DynamicZoneType type); - static DynamicZone* FindDynamicZoneByID(uint32_t dz_id); static void HandleZoneMessage(ServerPacket* pack); diff --git a/world/expedition.cpp b/world/expedition.cpp index a72275c94..723098013 100644 --- a/world/expedition.cpp +++ b/world/expedition.cpp @@ -30,37 +30,25 @@ extern ClientList client_list; extern ZSList zoneserver_list; -Expedition::Expedition(uint32_t expedition_id, const DynamicZone& dz, uint32_t leader_id -) : - m_expedition_id(expedition_id), - m_dynamic_zone(dz), - m_leader_id(leader_id), +Expedition::Expedition() : m_choose_leader_cooldown_timer{ static_cast(RuleI(Expedition, ChooseLeaderCooldownTime)) } { m_warning_cooldown_timer.Enable(); } -void Expedition::AddMember(uint32_t character_id) +void Expedition::SetDynamicZone(DynamicZone&& dz) { - if (!HasMember(character_id)) - { - m_member_ids.emplace_back(character_id); - } -} + dz.SetName(GetName()); + dz.SetLeaderName(GetLeaderName()); -bool Expedition::HasMember(uint32_t character_id) -{ - return std::any_of(m_member_ids.begin(), m_member_ids.end(), - [&](uint32_t member_id) { return member_id == character_id; }); + m_dynamic_zone = std::move(dz); } void Expedition::RemoveMember(uint32_t character_id) { - m_member_ids.erase(std::remove_if(m_member_ids.begin(), m_member_ids.end(), - [&](uint32_t member_id) { return member_id == character_id; } - ), m_member_ids.end()); + RemoveInternalMember(character_id); - if (character_id == m_leader_id) + if (character_id == m_leader.char_id) { ChooseNewLeader(); } @@ -68,7 +56,7 @@ void Expedition::RemoveMember(uint32_t character_id) void Expedition::ChooseNewLeader() { - if (m_member_ids.empty() || !m_choose_leader_cooldown_timer.Check()) + if (m_members.empty() || !m_choose_leader_cooldown_timer.Check()) { m_choose_leader_needed = true; return; @@ -76,34 +64,38 @@ void Expedition::ChooseNewLeader() // we don't track expedition member status in world so may choose a linkdead member // this is fine since it will trigger another change when that member goes offline - auto it = std::find_if(m_member_ids.begin(), m_member_ids.end(), [&](uint32_t member_id) { - auto member_cle = (member_id != m_leader_id) ? client_list.FindCLEByCharacterID(member_id) : nullptr; - return (member_id != m_leader_id && member_cle && member_cle->GetOnline() == CLE_Status::InZone); + auto it = std::find_if(m_members.begin(), m_members.end(), [&](const ExpeditionMember& member) { + if (member.char_id != m_leader.char_id) { + auto member_cle = client_list.FindCLEByCharacterID(member.char_id); + return (member_cle && member_cle->GetOnline() == CLE_Status::InZone); + } + return false; }); - if (it == m_member_ids.end()) + if (it == m_members.end()) { // no online members found, fallback to choosing any member - it = std::find_if(m_member_ids.begin(), m_member_ids.end(), - [&](uint32_t member_id) { return (member_id != m_leader_id); }); + it = std::find_if(m_members.begin(), m_members.end(), + [&](const ExpeditionMember& member) { return (member.char_id != m_leader.char_id); }); } - if (it != m_member_ids.end() && SetNewLeader(*it)) + if (it != m_members.end() && SetNewLeader(*it)) { m_choose_leader_needed = false; } } -bool Expedition::SetNewLeader(uint32_t character_id) +bool Expedition::SetNewLeader(const ExpeditionMember& member) { - if (!HasMember(character_id)) + if (!HasMember(member.char_id)) { return false; } - LogExpeditionsModerate("Replacing [{}] leader [{}] with [{}]", m_expedition_id, m_leader_id, character_id); - ExpeditionDatabase::UpdateLeaderID(m_expedition_id, character_id); - m_leader_id = character_id; + LogExpeditionsModerate("Replacing [{}] leader [{}] with [{}]", m_id, m_leader.name, member.name); + ExpeditionDatabase::UpdateLeaderID(m_id, member.char_id); + m_leader = member; + m_dynamic_zone.SetLeaderName(m_leader.name); SendZonesLeaderChanged(); return true; } @@ -133,7 +125,7 @@ void Expedition::SendZonesLeaderChanged() auto pack = std::make_unique(ServerOP_ExpeditionLeaderChanged, pack_size); auto buf = reinterpret_cast(pack->pBuffer); buf->expedition_id = GetID(); - buf->leader_id = m_leader_id; + buf->leader_id = m_leader.char_id; zoneserver_list.SendPacket(pack.get()); } diff --git a/world/expedition.h b/world/expedition.h index 2f48739df..11ae083ed 100644 --- a/world/expedition.h +++ b/world/expedition.h @@ -22,43 +22,34 @@ #define WORLD_EXPEDITION_H #include "dynamic_zone.h" +#include "../common/expedition_base.h" #include "../common/timer.h" -#include #include -#include -class Expedition +class Expedition : public ExpeditionBase { public: - Expedition() = default; - Expedition(uint32_t expedition_id, const DynamicZone& dz, uint32_t leader_id); + Expedition(); - void AddMember(uint32_t character_id); void RemoveMember(uint32_t character_id); - void RemoveAllMembers() { m_member_ids.clear(); } void CheckExpireWarning(); void CheckLeader(); void ChooseNewLeader(); DynamicZone& GetDynamicZone() { return m_dynamic_zone; } - uint32_t GetID() const { return m_expedition_id; } - bool HasMember(uint32_t character_id); - bool IsEmpty() const { return m_member_ids.empty(); } - bool IsValid() const { return m_expedition_id != 0; } bool Process(); + void SendZonesExpeditionDeleted(); void SendZonesExpireWarning(uint32_t minutes_remaining); - bool SetNewLeader(uint32_t new_leader_id); + void SetDynamicZone(DynamicZone&& dz); + bool SetNewLeader(const ExpeditionMember& member); private: void SendZonesLeaderChanged(); - uint32_t m_expedition_id = 0; - uint32_t m_leader_id = 0; bool m_choose_leader_needed = false; Timer m_choose_leader_cooldown_timer; Timer m_warning_cooldown_timer; DynamicZone m_dynamic_zone; - std::vector m_member_ids; }; #endif diff --git a/world/expedition_database.cpp b/world/expedition_database.cpp index 2f54d7f3d..c3738901a 100644 --- a/world/expedition_database.cpp +++ b/world/expedition_database.cpp @@ -71,90 +71,6 @@ void ExpeditionDatabase::PurgeExpiredCharacterLockouts() database.QueryDatabase(query); } -std::vector ExpeditionDatabase::LoadExpeditions(uint32_t select_expedition_id) -{ - std::vector expeditions; - - std::string query = SQL( - SELECT - expeditions.id, - expeditions.dynamic_zone_id, - instance_list.id, - instance_list.zone, - instance_list.version, - instance_list.start_time, - instance_list.duration, - expeditions.leader_id, - expedition_members.character_id - FROM expeditions - INNER JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id - INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id - INNER JOIN expedition_members ON expedition_members.expedition_id = expeditions.id - AND expedition_members.is_current_member = TRUE - ); - - if (select_expedition_id != 0) - { - query.append(fmt::format(" WHERE expeditions.id = {};", select_expedition_id)); - } - else - { - query.append(" ORDER BY expeditions.id;"); - } - - auto results = database.QueryDatabase(query); - if (results.Success()) - { - uint32_t last_expedition_id = 0; - - for (auto row = results.begin(); row != results.end(); ++row) - { - uint32_t expedition_id = strtoul(row[0], nullptr, 10); - - if (last_expedition_id != expedition_id) - { - DynamicZone dynamic_zone{ - static_cast(strtoul(row[1], nullptr, 10)), // dz_id - static_cast(strtoul(row[3], nullptr, 10)), // dz_zone_id - static_cast(strtoul(row[2], nullptr, 10)), // dz_instance_id - static_cast(strtoul(row[4], nullptr, 10)), // dz_zone_version - static_cast(strtoul(row[5], nullptr, 10)), // start_time - static_cast(strtoul(row[6], nullptr, 10)), // duration - DynamicZoneType::Expedition - }; - - expeditions.emplace_back( - expedition_id, - dynamic_zone, - static_cast(strtoul(row[7], nullptr, 10)) // leader_id - ); - } - - last_expedition_id = expedition_id; - - uint32_t member_id = static_cast(strtoul(row[8], nullptr, 10)); - expeditions.back().AddMember(member_id); - } - } - - return expeditions; -} - -Expedition ExpeditionDatabase::LoadExpedition(uint32_t expedition_id) -{ - LogExpeditions("Loading expedition [{}] for world cache", expedition_id); - - Expedition expedition; - - auto expeditions = LoadExpeditions(expedition_id); - if (!expeditions.empty()) - { - expedition = expeditions.front(); - } - - return expedition; -} - void ExpeditionDatabase::DeleteExpeditions(const std::vector& expedition_ids) { LogExpeditionsDetail("Deleting [{}] expedition(s)", expedition_ids.size()); diff --git a/world/expedition_database.h b/world/expedition_database.h index 8342a292a..b86fd8b5d 100644 --- a/world/expedition_database.h +++ b/world/expedition_database.h @@ -29,8 +29,6 @@ class Expedition; namespace ExpeditionDatabase { void DeleteExpeditions(const std::vector& expedition_ids); - std::vector LoadExpeditions(uint32_t select_expedition_id = 0); - Expedition LoadExpedition(uint32_t expedition_id); void MoveMembersToSafeReturn(const std::vector& expedition_ids); void PurgeExpiredExpeditions(); void PurgeExpiredCharacterLockouts(); diff --git a/world/expedition_message.cpp b/world/expedition_message.cpp index 46ecfa9cc..999dfd44a 100644 --- a/world/expedition_message.cpp +++ b/world/expedition_message.cpp @@ -43,22 +43,22 @@ void ExpeditionMessage::HandleZoneMessage(ServerPacket* pack) case ServerOP_ExpeditionCreate: { auto buf = reinterpret_cast(pack->pBuffer); - expedition_state.AddExpedition(buf->expedition_id); + expedition_state.CacheFromDatabase(buf->expedition_id); zoneserver_list.SendPacket(pack); break; } case ServerOP_ExpeditionMemberChange: { auto buf = reinterpret_cast(pack->pBuffer); - expedition_state.MemberChange(buf->expedition_id, buf->char_id, buf->removed); + expedition_state.MemberChange(buf->expedition_id, { buf->char_id, buf->char_name }, buf->removed); zoneserver_list.SendPacket(pack); break; } case ServerOP_ExpeditionMemberSwap: { auto buf = reinterpret_cast(pack->pBuffer); - expedition_state.MemberChange(buf->expedition_id, buf->add_char_id, false); - expedition_state.MemberChange(buf->expedition_id, buf->remove_char_id, true); + expedition_state.MemberChange(buf->expedition_id, { buf->add_char_id, buf->add_char_name }, false); + expedition_state.MemberChange(buf->expedition_id, { buf->remove_char_id, buf->remove_char_name }, true); zoneserver_list.SendPacket(pack); break; } @@ -141,7 +141,7 @@ void ExpeditionMessage::MakeLeader(ServerPacket* pack) auto expedition = expedition_state.GetExpedition(buf->expedition_id); if (expedition) { - buf->is_success = expedition->SetNewLeader(new_leader_cle->CharID()); + buf->is_success = expedition->SetNewLeader({ new_leader_cle->CharID(), new_leader_cle->name() }); } buf->is_online = true; diff --git a/world/expedition_state.cpp b/world/expedition_state.cpp index 815ef6c58..19693e279 100644 --- a/world/expedition_state.cpp +++ b/world/expedition_state.cpp @@ -21,7 +21,9 @@ #include "expedition_state.h" #include "expedition.h" #include "expedition_database.h" +#include "worlddb.h" #include "../common/eqemu_logsys.h" +#include "../common/repositories/expedition_members_repository.h" #include ExpeditionState expedition_state; @@ -29,66 +31,99 @@ ExpeditionState expedition_state; Expedition* ExpeditionState::GetExpedition(uint32_t expedition_id) { auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), - [&](const Expedition& expedition) { return expedition.GetID() == expedition_id; }); + [&](const std::unique_ptr& expedition) { + return expedition->GetID() == expedition_id; + }); - return (it != m_expeditions.end()) ? &(*it) : nullptr; + return (it != m_expeditions.end()) ? it->get() : nullptr; } Expedition* ExpeditionState::GetExpeditionByDynamicZoneID(uint32_t dz_id) { auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), - [&](Expedition& expedition) { return expedition.GetDynamicZone().GetID() == dz_id; }); + [&](const std::unique_ptr& expedition) { + return expedition->GetDynamicZone().GetID() == dz_id; + }); - return (it != m_expeditions.end()) ? &(*it) : nullptr; + return (it != m_expeditions.end()) ? it->get() : nullptr; } -void ExpeditionState::LoadActiveExpeditions() +void ExpeditionState::CacheFromDatabase(uint32_t expedition_id) { - BenchTimer benchmark; - - m_expeditions = ExpeditionDatabase::LoadExpeditions(); - - auto elapsed = benchmark.elapsed(); - LogExpeditions("World caching [{}] expeditions took [{}s]", m_expeditions.size(), elapsed); -} - -void ExpeditionState::AddExpedition(uint32_t expedition_id) -{ - if (expedition_id == 0) + if (expedition_id == 0 || GetExpedition(expedition_id)) { return; } - auto expedition = ExpeditionDatabase::LoadExpedition(expedition_id); + auto expedition = ExpeditionsRepository::GetWithLeaderName(database, expedition_id); + CacheExpeditions({ std::move(expedition) }); +} - if (expedition.IsValid()) +void ExpeditionState::CacheAllFromDatabase() +{ + BenchTimer benchmark; + + auto expeditions = ExpeditionsRepository::GetAllWithLeaderName(database); + m_expeditions.clear(); + m_expeditions.reserve(expeditions.size()); + + CacheExpeditions(std::move(expeditions)); + + LogExpeditions("Caching [{}] expedition(s) took [{}s]", m_expeditions.size(), benchmark.elapsed()); +} + +void ExpeditionState::CacheExpeditions( + std::vector&& expedition_entries) +{ + // bulk load expedition dzs and members before caching + std::vector expedition_ids; + std::vector dynamic_zone_ids; + for (const auto& entry : expedition_entries) { - auto existing_expedition = GetExpedition(expedition_id); - if (!existing_expedition) + expedition_ids.emplace_back(entry.id); + dynamic_zone_ids.emplace_back(entry.dynamic_zone_id); + } + + auto dynamic_zones = DynamicZonesRepository::GetWithInstance(database, dynamic_zone_ids); + auto expedition_members = ExpeditionMembersRepository::GetWithNames(database, expedition_ids); + + for (auto& entry : expedition_entries) + { + auto expedition = std::make_unique(); + expedition->LoadRepositoryResult(std::move(entry)); + + auto dz_entry_iter = std::find_if(dynamic_zones.begin(), dynamic_zones.end(), + [&](const DynamicZonesRepository::DynamicZoneInstance& dz_entry) { + return dz_entry.id == entry.dynamic_zone_id; + }); + + if (dz_entry_iter != dynamic_zones.end()) { - m_expeditions.emplace_back(expedition); + expedition->SetDynamicZone(std::move(*dz_entry_iter)); } + + for (auto& member : expedition_members) + { + if (member.expedition_id == expedition->GetID()) + { + expedition->AddMemberFromRepositoryResult(std::move(member)); + } + } + + m_expeditions.emplace_back(std::move(expedition)); } } -void ExpeditionState::RemoveExpedition(uint32_t expedition_id) -{ - m_expeditions.erase(std::remove_if(m_expeditions.begin(), m_expeditions.end(), - [&](const Expedition& expedition) { - return expedition.GetID() == expedition_id; - } - ), m_expeditions.end()); -} - -void ExpeditionState::MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove) +void ExpeditionState::MemberChange( + uint32_t expedition_id, const ExpeditionMember& member, bool remove) { auto expedition = GetExpedition(expedition_id); if (expedition) { if (remove) { - expedition->RemoveMember(character_id); + expedition->RemoveMember(member.char_id); } else { - expedition->AddMember(character_id); + expedition->AddInternalMember(member); } } } @@ -98,7 +133,7 @@ void ExpeditionState::RemoveAllMembers(uint32_t expedition_id) auto expedition = GetExpedition(expedition_id); if (expedition) { - expedition->RemoveAllMembers(); + expedition->ClearInternalMembers(); } } @@ -113,10 +148,10 @@ void ExpeditionState::Process() for (auto it = m_expeditions.begin(); it != m_expeditions.end();) { - bool is_deleted = it->Process(); + bool is_deleted = (*it)->Process(); if (is_deleted) { - expedition_ids.emplace_back(it->GetID()); + expedition_ids.emplace_back((*it)->GetID()); } it = is_deleted ? m_expeditions.erase(it) : it + 1; } diff --git a/world/expedition_state.h b/world/expedition_state.h index d7fb27d09..da8cdb306 100644 --- a/world/expedition_state.h +++ b/world/expedition_state.h @@ -21,6 +21,7 @@ #ifndef WORLD_EXPEDITION_STATE_H #define WORLD_EXPEDITION_STATE_H +#include "../common/repositories/expeditions_repository.h" #include "../common/rulesys.h" #include "../common/timer.h" #include @@ -29,21 +30,22 @@ extern class ExpeditionState expedition_state; class Expedition; +struct ExpeditionMember; class ExpeditionState { public: - void AddExpedition(uint32_t expedition_id); + void CacheExpeditions(std::vector&& expedition_entries); + void CacheFromDatabase(uint32_t expedition_id); + void CacheAllFromDatabase(); Expedition* GetExpedition(uint32_t expedition_id); Expedition* GetExpeditionByDynamicZoneID(uint32_t dz_id); - void LoadActiveExpeditions(); - void MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove); + void MemberChange(uint32_t expedition_id, const ExpeditionMember& member, bool remove); void Process(); void RemoveAllMembers(uint32_t expedition_id); - void RemoveExpedition(uint32_t expedition_id); private: - std::vector m_expeditions; + std::vector> m_expeditions; Timer m_process_throttle_timer{static_cast(RuleI(DynamicZone, WorldProcessRate))}; }; diff --git a/world/main.cpp b/world/main.cpp index a094c8b4f..f150db0e4 100644 --- a/world/main.cpp +++ b/world/main.cpp @@ -438,7 +438,7 @@ int main(int argc, char** argv) { PurgeInstanceTimer.Start(450000); LogInfo("Loading active expeditions"); - expedition_state.LoadActiveExpeditions(); + expedition_state.CacheAllFromDatabase(); LogInfo("Loading char create info"); content_db.LoadCharacterCreateAllocations(); diff --git a/zone/command.cpp b/zone/command.cpp index 709bb92c4..e49dea4d2 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -6900,20 +6900,20 @@ void command_dz(Client* c, const Seperator* sep) auto leader_saylink = EQ::SayLinkEngine::GenerateQuestSaylink(fmt::format( "#goto {}", expedition->GetLeaderName()), false, expedition->GetLeaderName()); auto zone_saylink = EQ::SayLinkEngine::GenerateQuestSaylink(fmt::format( - "#zoneinstance {}", expedition->GetInstanceID()), false, "zone"); + "#zoneinstance {}", expedition->GetDynamicZone().GetInstanceID()), false, "zone"); auto seconds = expedition->GetDynamicZone().GetSecondsRemaining(); c->Message(Chat::White, fmt::format( "expedition id: [{}] dz id: [{}] name: [{}] leader: [{}] {}: [{}]:[{}]:[{}]:[{}] members: [{}] remaining: [{:02}:{:02}:{:02}]", expedition->GetID(), - expedition->GetDynamicZoneID(), + expedition->GetDynamicZone().GetID(), expedition->GetName(), leader_saylink, zone_saylink, ZoneName(expedition->GetDynamicZone().GetZoneID()), expedition->GetDynamicZone().GetZoneID(), - expedition->GetInstanceID(), + expedition->GetDynamicZone().GetInstanceID(), expedition->GetDynamicZone().GetZoneVersion(), expedition->GetMemberCount(), seconds / 3600, // hours diff --git a/zone/dynamic_zone.cpp b/zone/dynamic_zone.cpp index 9d9f35012..0b19e5ade 100644 --- a/zone/dynamic_zone.cpp +++ b/zone/dynamic_zone.cpp @@ -64,22 +64,6 @@ DynamicZone* DynamicZone::FindDynamicZoneByID(uint32_t dz_id) return nullptr; } -std::unordered_map DynamicZone::LoadMultipleDzFromDatabase( - const std::vector& dynamic_zone_ids) -{ - LogDynamicZonesDetail("Loading dynamic zone data for [{}] instances", dynamic_zone_ids.size()); - - std::unordered_map dynamic_zones; - - auto entries = DynamicZonesRepository::GetWithInstance(database, dynamic_zone_ids); - for (auto& entry : entries) - { - dynamic_zones.emplace(entry.id, std::move(entry)); - } - - return dynamic_zones; -} - void DynamicZone::StartAllClientRemovalTimers() { for (const auto& client_iter : entity_list.GetClientList()) diff --git a/zone/dynamic_zone.h b/zone/dynamic_zone.h index 98949953d..3b421330a 100644 --- a/zone/dynamic_zone.h +++ b/zone/dynamic_zone.h @@ -42,8 +42,6 @@ public: DynamicZone(uint32_t zone_id, uint32_t version, uint32_t duration, DynamicZoneType type); static DynamicZone* FindDynamicZoneByID(uint32_t dz_id); - static std::unordered_map LoadMultipleDzFromDatabase( - const std::vector& dynamic_zone_ids); static void HandleWorldMessage(ServerPacket* pack); void SetSecondsRemaining(uint32_t seconds_remaining) override; diff --git a/zone/expedition.cpp b/zone/expedition.cpp index 27bb86079..0c1481d7d 100644 --- a/zone/expedition.cpp +++ b/zone/expedition.cpp @@ -27,6 +27,8 @@ #include "zonedb.h" #include "../common/eqemu_logsys.h" #include "../common/expedition_lockout_timer.h" +#include "../common/repositories/expedition_lockouts_repository.h" +#include "../common/repositories/expedition_members_repository.h" #include "../common/util/uuid.h" extern WorldServer worldserver; @@ -49,13 +51,7 @@ const int32_t Expedition::EVENT_TIMER_ID = 1; Expedition::Expedition( uint32_t id, const std::string& uuid, DynamicZone&& dz, const std::string& expedition_name, const ExpeditionMember& leader, uint32_t min_players, uint32_t max_players -) : - m_id(id), - m_uuid(uuid), - m_expedition_name(expedition_name), - m_leader(leader), - m_min_players(min_players), - m_max_players(max_players) +) : ExpeditionBase(id, uuid, expedition_name, leader, min_players, max_players) { SetDynamicZone(std::move(dz)); } @@ -122,7 +118,7 @@ Expedition* Expedition::TryCreate( "Created [{}] [{}] instance id: [{}] leader: [{}] minplayers: [{}] maxplayers: [{}]", expedition->GetID(), expedition->GetName(), - expedition->GetInstanceID(), + expedition->GetDynamicZone().GetInstanceID(), expedition->GetLeaderName(), expedition->GetMinPlayers(), expedition->GetMaxPlayers() @@ -150,113 +146,88 @@ Expedition* Expedition::TryCreate( return nullptr; } -void Expedition::CacheExpeditions(MySQLRequestResult& results) +void Expedition::CacheExpeditions( + std::vector&& expedition_entries) { - if (!results.Success() || !zone) + if (!zone) { return; } + // bulk load expedition dzs, members, and internal lockouts before caching std::vector expedition_ids; - std::vector dynamic_zone_ids;; - std::vector> expedition_character_ids; - - using col = LoadExpeditionColumns::eLoadExpeditionColumns; - - uint32_t last_expedition_id = 0; - - for (auto row = results.begin(); row != results.end(); ++row) + std::vector dynamic_zone_ids; + for (const auto& entry : expedition_entries) { - auto expedition_id = strtoul(row[col::id], nullptr, 10); + expedition_ids.emplace_back(entry.id); + dynamic_zone_ids.emplace_back(entry.dynamic_zone_id); + } - if (expedition_id != last_expedition_id) + auto dynamic_zones = DynamicZonesRepository::GetWithInstance(database, dynamic_zone_ids); + auto expedition_members = ExpeditionMembersRepository::GetWithNames(database, expedition_ids); + auto expedition_lockouts = ExpeditionLockoutsRepository::GetWithTimestamp(database, expedition_ids); + + std::vector> expedition_character_ids; // for online status request + + for (auto& entry : expedition_entries) + { + auto expedition = std::make_unique(); + expedition->LoadRepositoryResult(std::move(entry)); + + auto dz_entry_iter = std::find_if(dynamic_zones.begin(), dynamic_zones.end(), + [&](const DynamicZonesRepository::DynamicZoneInstance& dz_entry) { + return dz_entry.id == entry.dynamic_zone_id; + }); + + if (dz_entry_iter != dynamic_zones.end()) { - expedition_ids.emplace_back(expedition_id); - - uint32_t leader_id = strtoul(row[col::leader_id], nullptr, 10); - uint32_t dynamic_zone_id = strtoul(row[col::dz_id], nullptr, 10); - - dynamic_zone_ids.emplace_back(dynamic_zone_id); - - std::unique_ptr expedition = std::make_unique( - expedition_id, - row[col::uuid], // expedition uuid - DynamicZone{ dynamic_zone_id }, - row[col::expedition_name], // expedition name - ExpeditionMember{ leader_id, row[col::leader_name] }, // expedition leader id, name - strtoul(row[col::min_players], nullptr, 10), // min_players - strtoul(row[col::max_players], nullptr, 10) // max_players - ); - - bool add_replay_on_join = (strtoul(row[col::add_replay_on_join], nullptr, 10) != 0); - bool is_locked = (strtoul(row[col::is_locked], nullptr, 10) != 0); - - expedition->SetReplayLockoutOnMemberJoin(add_replay_on_join); - expedition->SetLocked(is_locked, ExpeditionLockMessage::None); - - zone->expedition_cache.emplace(expedition_id, std::move(expedition)); + expedition->SetDynamicZone(std::move(*dz_entry_iter)); } - last_expedition_id = expedition_id; - - // looping expedition members - auto current_expedition = Expedition::FindCachedExpeditionByID(last_expedition_id); - if (current_expedition) + for (auto& member : expedition_members) { - auto member_id = strtoul(row[col::member_id], nullptr, 10); - current_expedition->AddInternalMember( - row[col::member_name], member_id, ExpeditionMemberStatus::Offline); - expedition_character_ids.emplace_back(expedition_id, member_id); + if (member.expedition_id == expedition->GetID()) + { + expedition->AddMemberFromRepositoryResult(std::move(member)); + expedition_character_ids.emplace_back(expedition->GetID(), member.character_id); + } } + + for (auto& lockout_entry : expedition_lockouts) + { + if (lockout_entry.expedition_id == expedition->GetID()) + { + ExpeditionLockoutTimer lockout{ + std::move(lockout_entry.from_expedition_uuid), + expedition->GetName(), + std::move(lockout_entry.event_name), + static_cast(lockout_entry.expire_time), + static_cast(lockout_entry.duration) + }; + + std::string event_name = lockout.GetEventName(); // copy for key since we're moving it + expedition->m_lockouts.emplace(std::move(event_name), std::move(lockout)); + } + } + + auto inserted = zone->expedition_cache.emplace(entry.id, std::move(expedition)); + inserted.first->second->SendUpdatesToZoneMembers(); } // ask world for online members from all cached expeditions at once Expedition::SendWorldGetOnlineMembers(expedition_character_ids); - - // bulk load dynamic zone data and expedition lockouts for cached expeditions - auto dynamic_zones = DynamicZone::LoadMultipleDzFromDatabase(dynamic_zone_ids); - auto expedition_lockouts = ExpeditionDatabase::LoadMultipleExpeditionLockouts(expedition_ids); - - for (const auto& expedition_id : expedition_ids) - { - auto expedition = Expedition::FindCachedExpeditionByID(expedition_id); - if (expedition) - { - auto dz_iter = dynamic_zones.find(expedition->GetDynamicZoneID()); - if (dz_iter != dynamic_zones.end()) - { - expedition->SetDynamicZone(std::move(dz_iter->second)); - } - - auto lockout_iter = expedition_lockouts.find(expedition->GetID()); - if (lockout_iter != expedition_lockouts.end()) - { - expedition->m_lockouts = lockout_iter->second; - } - - // send member updates now that all data is loaded for the cached expedition - expedition->SendUpdatesToZoneMembers(); - } - } } void Expedition::CacheFromDatabase(uint32_t expedition_id) { - if (zone) + if (zone && expedition_id != 0) { BenchTimer benchmark; - auto results = ExpeditionDatabase::LoadExpedition(expedition_id); - if (!results.Success()) - { - LogExpeditions("Failed to load Expedition [{}] for zone cache", expedition_id); - return; - } + auto expedition = ExpeditionsRepository::GetWithLeaderName(database, expedition_id); + CacheExpeditions({ std::move(expedition) }); - CacheExpeditions(results); - - auto elapsed = benchmark.elapsed(); - LogExpeditions("Caching new expedition [{}] took [{}s]", expedition_id, elapsed); + LogExpeditions("Caching new expedition [{}] took [{}s]", expedition_id, benchmark.elapsed()); } } @@ -269,20 +240,13 @@ bool Expedition::CacheAllFromDatabase() BenchTimer benchmark; + auto expeditions = ExpeditionsRepository::GetAllWithLeaderName(database); zone->expedition_cache.clear(); + zone->expedition_cache.reserve(expeditions.size()); - // load all active expeditions and members to current zone cache - auto results = ExpeditionDatabase::LoadAllExpeditions(); - if (!results.Success()) - { - LogExpeditions("Failed to load Expeditions for zone cache"); - return false; - } + CacheExpeditions(std::move(expeditions)); - CacheExpeditions(results); - - auto elapsed = benchmark.elapsed(); - LogExpeditions("Caching [{}] expedition(s) took [{}s]", zone->expedition_cache.size(), elapsed); + LogExpeditions("Caching [{}] expedition(s) took [{}s]", zone->expedition_cache.size(), benchmark.elapsed()); return true; } @@ -391,48 +355,6 @@ bool Expedition::HasReplayLockout() return HasLockout(DZ_REPLAY_TIMER_NAME); } -bool Expedition::HasMember(uint32_t character_id) -{ - return std::any_of(m_members.begin(), m_members.end(), [&](const ExpeditionMember& member) { - return member.char_id == character_id; - }); -} - -bool Expedition::HasMember(const std::string& character_name) -{ - return std::any_of(m_members.begin(), m_members.end(), [&](const ExpeditionMember& member) { - return (strcasecmp(member.name.c_str(), character_name.c_str()) == 0); - }); -} - -ExpeditionMember Expedition::GetMemberData(uint32_t character_id) -{ - auto it = std::find_if(m_members.begin(), m_members.end(), [&](const ExpeditionMember& member) { - return member.char_id == character_id; - }); - - ExpeditionMember member_data; - if (it != m_members.end()) - { - member_data = *it; - } - return member_data; -} - -ExpeditionMember Expedition::GetMemberData(const std::string& character_name) -{ - auto it = std::find_if(m_members.begin(), m_members.end(), [&](const ExpeditionMember& member) { - return (strcasecmp(member.name.c_str(), character_name.c_str()) == 0); - }); - - ExpeditionMember member_data; - if (it != m_members.end()) - { - member_data = *it; - } - return member_data; -} - void Expedition::SetReplayLockoutOnMemberJoin(bool add_on_join, bool update_db) { m_add_replay_on_join = add_on_join; @@ -526,20 +448,6 @@ void Expedition::RemoveLockout(const std::string& event_name) SendWorldLockoutUpdate(lockout, true); } -void Expedition::AddInternalMember( - const std::string& char_name, uint32_t character_id, ExpeditionMemberStatus status) -{ - auto it = std::find_if(m_members.begin(), m_members.end(), - [character_id](const ExpeditionMember& member) { - return member.char_id == character_id; - }); - - if (it == m_members.end()) - { - m_members.emplace_back(character_id, char_name, status); - } -} - bool Expedition::AddMember(const std::string& add_char_name, uint32_t add_char_id) { if (HasMember(add_char_id)) @@ -644,10 +552,7 @@ void Expedition::UpdateMemberStatus(uint32_t update_member_id, ExpeditionMemberS } // if zone already had this member status cached avoid packet update to clients - auto it = std::find_if(m_members.begin(), m_members.end(), - [&](const ExpeditionMember& member) { return member.char_id == update_member_id; }); - - if (it != m_members.end() && it->status == status) + if (member_data.status == status) { return; } @@ -1197,7 +1102,7 @@ void Expedition::ProcessMemberAdded(const std::string& char_name, uint32_t added leader_client->MessageString(Chat::Yellow, EXPEDITION_MEMBER_ADDED, char_name.c_str(), m_expedition_name.c_str()); } - AddInternalMember(char_name, added_char_id, ExpeditionMemberStatus::Online); + AddInternalMember({ added_char_id, char_name, ExpeditionMemberStatus::Online }); Client* member_client = entity_list.GetClientByCharID(added_char_id); if (member_client) diff --git a/zone/expedition.h b/zone/expedition.h index 5b2a40043..d6e906fc7 100644 --- a/zone/expedition.h +++ b/zone/expedition.h @@ -22,8 +22,9 @@ #define EXPEDITION_H #include "dynamic_zone.h" -#include "../common/eq_constants.h" +#include "../common/expedition_base.h" #include "../common/expedition_lockout_timer.h" +#include "../common/repositories/expeditions_repository.h" #include #include #include @@ -34,21 +35,11 @@ class Client; class EQApplicationPacket; struct ExpeditionInvite; class ExpeditionRequest; -class MySQLRequestResult; class ServerPacket; extern const char* const DZ_YOU_NOT_ASSIGNED; extern const char* const EXPEDITION_OTHER_BELONGS; -enum class ExpeditionMemberStatus : uint8_t -{ - Unknown = 0, - Online, - Offline, - InDynamicZone, - LinkDead -}; - enum class ExpeditionLockMessage : uint8_t { None = 0, @@ -56,25 +47,10 @@ enum class ExpeditionLockMessage : uint8_t Begin }; -struct ExpeditionMember -{ - uint32_t char_id = 0; - std::string name; - ExpeditionMemberStatus status = ExpeditionMemberStatus::Online; - - ExpeditionMember() = default; - ExpeditionMember(uint32_t char_id_, const std::string& name_) - : char_id(char_id_), name(name_) {} - ExpeditionMember(uint32_t char_id_, const std::string& name_, ExpeditionMemberStatus status_) - : char_id(char_id_), name(name_), status(status_) {} - - bool IsValid() const { return char_id != 0 && !name.empty(); } -}; - -class Expedition +class Expedition : public ExpeditionBase { public: - Expedition() = delete; + Expedition() = default; Expedition(uint32_t id, const std::string& uuid, DynamicZone&& dz, const std::string& expedition_name, const ExpeditionMember& leader, uint32_t min_players, uint32_t max_players); @@ -103,23 +79,10 @@ public: const std::string& expedition_name = {}, const std::string& event_name = {}); static void AddLockoutClients(const ExpeditionLockoutTimer& lockout, uint32_t exclude_id = 0); - uint32_t GetDynamicZoneID() const { return m_dynamiczone.GetID(); } - uint32_t GetID() const { return m_id; } - uint16_t GetInstanceID() const { return m_dynamiczone.GetInstanceID(); } - uint32_t GetLeaderID() const { return m_leader.char_id; } - uint32_t GetMinPlayers() const { return m_min_players; } - uint32_t GetMaxPlayers() const { return m_max_players; } - uint32_t GetMemberCount() const { return static_cast(m_members.size()); } DynamicZone& GetDynamicZone() { return m_dynamiczone; } - const std::string& GetName() const { return m_expedition_name; } - const std::string& GetLeaderName() const { return m_leader.name; } - const std::string& GetUUID() const { return m_uuid; } const std::unordered_map& GetLockouts() const { return m_lockouts; } - const std::vector& GetMembers() const { return m_members; } bool AddMember(const std::string& add_char_name, uint32_t add_char_id); - bool HasMember(const std::string& character_name); - bool HasMember(uint32_t character_id); void RemoveAllMembers(bool enable_removal_timers = true); bool RemoveMember(const std::string& remove_char_name); void SetMemberStatus(Client* client, ExpeditionMemberStatus status); @@ -164,13 +127,12 @@ public: static const int32_t EVENT_TIMER_ID; private: - static void CacheExpeditions(MySQLRequestResult& results); + static void CacheExpeditions(std::vector&& expeditions); static void SendWorldGetOnlineMembers(const std::vector>& expedition_character_ids); static void SendWorldCharacterLockout(uint32_t character_id, const ExpeditionLockoutTimer& lockout, bool remove); void AddLockout(const ExpeditionLockoutTimer& lockout, bool members_only = false); void AddLockoutDurationClients(const ExpeditionLockoutTimer& lockout, int seconds, uint32_t exclude_id = 0); - void AddInternalMember(const std::string& char_name, uint32_t char_id, ExpeditionMemberStatus status); bool ConfirmLeaderCommand(Client* requester); bool ProcessAddConflicts(Client* leader_client, Client* add_client, bool swapping); void ProcessLeaderChanged(uint32_t new_leader_id); @@ -207,8 +169,6 @@ private: const std::string& swap_remove_name, Client* leader_client = nullptr); void UpdateMemberStatus(uint32_t update_character_id, ExpeditionMemberStatus status); - ExpeditionMember GetMemberData(uint32_t character_id); - ExpeditionMember GetMemberData(const std::string& character_name); std::unique_ptr CreateExpireWarningPacket(uint32_t minutes_remaining); std::unique_ptr CreateInfoPacket(bool clear = false); std::unique_ptr CreateInvitePacket(const std::string& inviter_name, const std::string& swap_remove_name); @@ -217,16 +177,7 @@ private: std::unique_ptr CreateMemberListStatusPacket(const std::string& name, ExpeditionMemberStatus status); std::unique_ptr CreateLeaderNamePacket(); - uint32_t m_id = 0; - uint32_t m_min_players = 0; - uint32_t m_max_players = 0; - bool m_is_locked = false; - bool m_add_replay_on_join = true; - std::string m_uuid; - std::string m_expedition_name; DynamicZone m_dynamiczone { DynamicZoneType::Expedition }; - ExpeditionMember m_leader; - std::vector m_members; std::unordered_map m_lockouts; std::unordered_map m_npc_loot_events; // only valid inside dz zone std::unordered_map m_spawn_loot_events; // only valid inside dz zone diff --git a/zone/expedition_database.cpp b/zone/expedition_database.cpp index d628d8fd1..e1b5c0bf6 100644 --- a/zone/expedition_database.cpp +++ b/zone/expedition_database.cpp @@ -51,52 +51,6 @@ uint32_t ExpeditionDatabase::InsertExpedition( return results.LastInsertedID(); } -std::string ExpeditionDatabase::LoadExpeditionsSelectQuery() -{ - return std::string(SQL( - SELECT - expeditions.id, - expeditions.uuid, - expeditions.dynamic_zone_id, - expeditions.expedition_name, - expeditions.leader_id, - expeditions.min_players, - expeditions.max_players, - expeditions.add_replay_on_join, - expeditions.is_locked, - character_data.name leader_name, - expedition_members.character_id, - member_data.name - FROM expeditions - INNER JOIN character_data ON expeditions.leader_id = character_data.id - INNER JOIN expedition_members ON expeditions.id = expedition_members.expedition_id - AND expedition_members.is_current_member = TRUE - INNER JOIN character_data member_data ON expedition_members.character_id = member_data.id - )); -} - -MySQLRequestResult ExpeditionDatabase::LoadExpedition(uint32_t expedition_id) -{ - LogExpeditionsDetail("Loading expedition [{}]", expedition_id); - - std::string query = fmt::format(SQL( - {} WHERE expeditions.id = {}; - ), LoadExpeditionsSelectQuery(), expedition_id); - - return database.QueryDatabase(query); -} - -MySQLRequestResult ExpeditionDatabase::LoadAllExpeditions() -{ - LogExpeditionsDetail("Loading all expeditions from database"); - - std::string query = fmt::format(SQL( - {} ORDER BY expeditions.id; - ), LoadExpeditionsSelectQuery()); - - return database.QueryDatabase(query); -} - std::vector ExpeditionDatabase::LoadCharacterLockouts(uint32_t character_id) { LogExpeditionsDetail("Loading character [{}] lockouts", character_id); @@ -170,54 +124,6 @@ std::vector ExpeditionDatabase::LoadCharacterLockouts( return lockouts; } -std::unordered_map> -ExpeditionDatabase::LoadMultipleExpeditionLockouts( - const std::vector& expedition_ids) -{ - LogExpeditionsDetail("Loading internal lockouts for [{}] expeditions", expedition_ids.size()); - - std::string in_expedition_ids_query = fmt::format("{}", fmt::join(expedition_ids, ",")); - - // these are loaded into the same container type expeditions use to store lockouts - std::unordered_map> lockouts; - - if (!in_expedition_ids_query.empty()) - { - std::string query = fmt::format(SQL( - SELECT - expedition_lockouts.expedition_id, - expedition_lockouts.from_expedition_uuid, - expeditions.expedition_name, - expedition_lockouts.event_name, - UNIX_TIMESTAMP(expedition_lockouts.expire_time), - expedition_lockouts.duration - FROM expedition_lockouts - INNER JOIN expeditions ON expedition_lockouts.expedition_id = expeditions.id - WHERE expedition_id IN ({}) - ORDER BY expedition_id; - ), in_expedition_ids_query); - - auto results = database.QueryDatabase(query); - - if (results.Success()) - { - for (auto row = results.begin(); row != results.end(); ++row) - { - auto expedition_id = strtoul(row[0], nullptr, 10); - lockouts[expedition_id].emplace(row[3], ExpeditionLockoutTimer{ - row[1], // expedition_uuid - row[2], // expedition_name - row[3], // event_name - strtoull(row[4], nullptr, 10), // expire_time - static_cast(strtoul(row[5], nullptr, 10)) // original duration - }); - } - } - } - - return lockouts; -} - void ExpeditionDatabase::DeleteAllCharacterLockouts(uint32_t character_id) { LogExpeditionsDetail("Deleting all character [{}] lockouts", character_id); diff --git a/zone/expedition_database.h b/zone/expedition_database.h index 2c72ee9ad..9e0487b36 100644 --- a/zone/expedition_database.h +++ b/zone/expedition_database.h @@ -38,14 +38,9 @@ namespace ExpeditionDatabase uint32_t InsertExpedition( const std::string& uuid, uint32_t instance_id, const std::string& expedition_name, uint32_t leader_id, uint32_t min_players, uint32_t max_players); - std::string LoadExpeditionsSelectQuery(); - MySQLRequestResult LoadExpedition(uint32_t expedition_id); - MySQLRequestResult LoadAllExpeditions(); std::vector LoadCharacterLockouts(uint32_t character_id); std::vector LoadCharacterLockouts(uint32_t character_id, const std::string& expedition_name); - std::unordered_map> - LoadMultipleExpeditionLockouts(const std::vector& expedition_ids); void DeleteAllMembers(uint32_t expedition_id); void DeleteMember(uint32_t expedition_id, uint32_t character_id); void DeleteAllCharacterLockouts(uint32_t character_id); @@ -73,23 +68,4 @@ namespace ExpeditionDatabase const ExpeditionLockoutTimer& lockout, int seconds); }; -namespace LoadExpeditionColumns -{ - enum eLoadExpeditionColumns - { - id = 0, - uuid, - dz_id, - expedition_name, - leader_id, - min_players, - max_players, - add_replay_on_join, - is_locked, - leader_name, - member_id, - member_name - }; -}; - #endif diff --git a/zone/lua_expedition.cpp b/zone/lua_expedition.cpp index 1bd872cc2..434cc5726 100644 --- a/zone/lua_expedition.cpp +++ b/zone/lua_expedition.cpp @@ -59,7 +59,7 @@ void Lua_Expedition::AddReplayLockoutDuration(int seconds, bool members_only) { uint32_t Lua_Expedition::GetDynamicZoneID() { Lua_Safe_Call_Int(); - return self->GetDynamicZoneID(); + return self->GetDynamicZone().GetID(); } uint32_t Lua_Expedition::GetID() { diff --git a/zone/perl_expedition.cpp b/zone/perl_expedition.cpp index 3095c3770..ccba1e6a8 100644 --- a/zone/perl_expedition.cpp +++ b/zone/perl_expedition.cpp @@ -142,7 +142,7 @@ XS(XS_Expedition_GetDynamicZoneID) { Expedition* THIS = nullptr; VALIDATE_THIS_IS_EXPEDITION; - XSRETURN_UV(THIS->GetDynamicZoneID()); + XSRETURN_UV(THIS->GetDynamicZone().GetID()); } XS(XS_Expedition_GetID); @@ -168,7 +168,7 @@ XS(XS_Expedition_GetInstanceID) { Expedition* THIS = nullptr; VALIDATE_THIS_IS_EXPEDITION; - XSRETURN_UV(THIS->GetInstanceID()); + XSRETURN_UV(THIS->GetDynamicZone().GetInstanceID()); } XS(XS_Expedition_GetLeaderName);