diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 08db085853..084ac9c4f4 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -177,10 +177,10 @@ SET(repositories repositories/base/base_discovered_items_repository.h repositories/base/base_doors_repository.h repositories/base/base_dynamic_zones_repository.h + repositories/base/base_dynamic_zone_members_repository.h repositories/base/base_eventlog_repository.h repositories/base/base_expeditions_repository.h repositories/base/base_expedition_lockouts_repository.h - repositories/base/base_expedition_members_repository.h repositories/base/base_faction_base_data_repository.h repositories/base/base_faction_list_repository.h repositories/base/base_faction_list_mod_repository.h @@ -341,10 +341,10 @@ SET(repositories repositories/discovered_items_repository.h repositories/doors_repository.h repositories/dynamic_zones_repository.h + repositories/dynamic_zone_members_repository.h repositories/eventlog_repository.h repositories/expeditions_repository.h repositories/expedition_lockouts_repository.h - repositories/expedition_members_repository.h repositories/faction_base_data_repository.h repositories/faction_list_repository.h repositories/faction_list_mod_repository.h diff --git a/common/database_instances.cpp b/common/database_instances.cpp index 0c4be4bd6e..75edd9fd32 100644 --- a/common/database_instances.cpp +++ b/common/database_instances.cpp @@ -20,6 +20,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../common/rulesys.h" #include "../common/string_util.h" #include "../common/timer.h" +#include "../common/repositories/dynamic_zone_members_repository.h" +#include "../common/repositories/dynamic_zones_repository.h" #include "database.h" @@ -493,8 +495,8 @@ void Database::DeleteInstance(uint16 instance_id) query = StringFormat("DELETE FROM spawn_condition_values WHERE instance_id=%u", instance_id); QueryDatabase(query); - query = fmt::format("DELETE FROM dynamic_zones WHERE instance_id={}", instance_id); - QueryDatabase(query); + DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id); + DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id)); BuryCorpsesInInstance(instance_id); } @@ -585,7 +587,8 @@ void Database::PurgeExpiredInstances() QueryDatabase(fmt::format("DELETE FROM respawn_times WHERE instance_id IN ({})", imploded_instance_ids)); QueryDatabase(fmt::format("DELETE FROM spawn_condition_values WHERE instance_id IN ({})", imploded_instance_ids)); QueryDatabase(fmt::format("UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id IN ({})", imploded_instance_ids)); - QueryDatabase(fmt::format("DELETE FROM dynamic_zones WHERE instance_id IN ({})", imploded_instance_ids)); + DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids); + DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids)); } void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration) diff --git a/common/database_schema.h b/common/database_schema.h index 8d8e81441d..b338a9bc51 100644 --- a/common/database_schema.h +++ b/common/database_schema.h @@ -309,10 +309,10 @@ namespace DatabaseSchema { "banned_ips", "bug_reports", "bugs", + "dynamic_zone_members", "dynamic_zones", "eventlog", "expedition_lockouts", - "expedition_members", "expeditions", "gm_ips", "group_id", diff --git a/common/dynamic_zone_base.cpp b/common/dynamic_zone_base.cpp index 8e29722d36..f3a499ee85 100644 --- a/common/dynamic_zone_base.cpp +++ b/common/dynamic_zone_base.cpp @@ -3,6 +3,7 @@ #include "eqemu_logsys.h" #include "repositories/instance_list_repository.h" #include "repositories/instance_list_player_repository.h" +#include "rulesys.h" #include "servertalk.h" DynamicZoneBase::DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& entry) @@ -99,6 +100,13 @@ void DynamicZoneBase::LoadRepositoryResult(DynamicZonesRepository::DynamicZoneIn m_expire_time = m_start_time + m_duration; } +void DynamicZoneBase::AddMemberFromRepositoryResult( + DynamicZoneMembersRepository::MemberWithName&& entry) +{ + auto status = DynamicZoneMemberStatus::Unknown; + AddInternalMember({ entry.character_id, std::move(entry.character_name), status }); +} + uint32_t DynamicZoneBase::SaveToDatabase() { LogDynamicZonesDetail("Saving dz instance [{}] to database", m_instance_id); @@ -131,12 +139,14 @@ uint32_t DynamicZoneBase::SaveToDatabase() void DynamicZoneBase::AddCharacter(uint32_t character_id) { + DynamicZoneMembersRepository::AddMember(GetDatabase(), m_id, character_id); GetDatabase().AddClientToInstance(m_instance_id, character_id); SendInstanceAddRemoveCharacter(character_id, false); // stops client kick timer } void DynamicZoneBase::RemoveCharacter(uint32_t character_id) { + DynamicZoneMembersRepository::RemoveMember(GetDatabase(), m_id, character_id); GetDatabase().RemoveClientFromInstance(m_instance_id, character_id); SendInstanceAddRemoveCharacter(character_id, true); // start client kick timer } @@ -153,24 +163,35 @@ void DynamicZoneBase::RemoveAllCharacters(bool enable_removal_timers) SendInstanceRemoveAllCharacters(); } + DynamicZoneMembersRepository::RemoveAllMembers(GetDatabase(), m_id); GetDatabase().RemoveClientsFromInstance(GetInstanceID()); } -void DynamicZoneBase::SaveInstanceMembersToDatabase(const std::vector& character_ids) +void DynamicZoneBase::SaveMembers(const std::vector& members) { - LogDynamicZonesDetail("Saving [{}] members for instance [{}]", character_ids.size(), m_instance_id); + LogDynamicZonesDetail("Saving [{}] member(s) for dz [{}]", members.size(), m_id); - std::vector insert_players; + m_members = members; - for (const auto& character_id : character_ids) + // the lower level instance_list_players needs to be kept updated as well + std::vector insert_members; + std::vector insert_players; + for (const auto& member : m_members) { - InstanceListPlayerRepository::InstanceListPlayer entry{}; - entry.id = static_cast(m_instance_id); - entry.charid = static_cast(character_id); - insert_players.emplace_back(entry); + DynamicZoneMembersRepository::DynamicZoneMembers member_entry{}; + member_entry.dynamic_zone_id = m_id; + member_entry.character_id = member.id; + member_entry.is_current_member = true; + insert_members.emplace_back(member_entry); + + InstanceListPlayerRepository::InstanceListPlayer player_entry; + player_entry.id = static_cast(m_instance_id); + player_entry.charid = static_cast(member.id); + insert_players.emplace_back(player_entry); } - InstanceListPlayerRepository::InsertMany(GetDatabase(), insert_players); + DynamicZoneMembersRepository::InsertOrUpdateMany(GetDatabase(), insert_members); + InstanceListPlayerRepository::InsertOrUpdateMany(GetDatabase(), insert_players); } void DynamicZoneBase::SetCompass(const DynamicZoneLocation& location, bool update_db) @@ -287,3 +308,123 @@ std::unique_ptr DynamicZoneBase::CreateServerDzLocationPacket( return pack; } + +uint32_t DynamicZoneBase::GetDatabaseMemberCount() +{ + return DynamicZoneMembersRepository::GetCountWhere(GetDatabase(), + fmt::format("dynamic_zone_id = {} AND is_current_member = TRUE", m_id)); +} + +bool DynamicZoneBase::HasDatabaseMember(uint32_t character_id) +{ + if (character_id == 0) + { + return false; + } + + auto entries = DynamicZoneMembersRepository::GetWhere(GetDatabase(), fmt::format( + "dynamic_zone_id = {} AND character_id = {} AND is_current_member = TRUE", + m_id, character_id + )); + + return entries.size() != 0; +} + +void DynamicZoneBase::AddInternalMember(const DynamicZoneMember& member) +{ + if (!HasMember(member.id)) + { + m_members.emplace_back(member); + } +} + +void DynamicZoneBase::RemoveInternalMember(uint32_t character_id) +{ + m_members.erase(std::remove_if(m_members.begin(), m_members.end(), + [&](const DynamicZoneMember& member) { return member.id == character_id; } + ), m_members.end()); +} + +bool DynamicZoneBase::HasMember(uint32_t character_id) +{ + return std::any_of(m_members.begin(), m_members.end(), + [&](const DynamicZoneMember& member) { return member.id == character_id; }); +} + +bool DynamicZoneBase::HasMember(const std::string& character_name) +{ + return std::any_of(m_members.begin(), m_members.end(), + [&](const DynamicZoneMember& member) { + return strcasecmp(member.name.c_str(), character_name.c_str()) == 0; + }); +} + +DynamicZoneMember DynamicZoneBase::GetMemberData(uint32_t character_id) +{ + auto it = std::find_if(m_members.begin(), m_members.end(), + [&](const DynamicZoneMember& member) { return member.id == character_id; }); + + DynamicZoneMember member_data; + if (it != m_members.end()) + { + member_data = *it; + } + return member_data; +} + +DynamicZoneMember DynamicZoneBase::GetMemberData(const std::string& character_name) +{ + auto it = std::find_if(m_members.begin(), m_members.end(), + [&](const DynamicZoneMember& member) { + return strcasecmp(member.name.c_str(), character_name.c_str()) == 0; + }); + + DynamicZoneMember member_data; + if (it != m_members.end()) + { + member_data = *it; + } + return member_data; +} + +bool DynamicZoneBase::SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status) +{ + if (status == DynamicZoneMemberStatus::InDynamicZone && !RuleB(DynamicZone, EnableInDynamicZoneStatus)) + { + status = DynamicZoneMemberStatus::Online; + } + + if (character_id == m_leader.id) + { + m_leader.status = status; + } + + auto it = std::find_if(m_members.begin(), m_members.end(), + [&](const DynamicZoneMember& member) { return member.id == character_id; }); + + if (it != m_members.end() && it->status != status) + { + it->status = status; + return true; + } + + return false; +} + +std::string DynamicZoneBase::GetDynamicZoneTypeName(DynamicZoneType dz_type) +{ + switch (dz_type) + { + case DynamicZoneType::Expedition: + return "Expedition"; + case DynamicZoneType::Tutorial: + return "Tutorial"; + case DynamicZoneType::Task: + return "Task"; + case DynamicZoneType::Mission: + return "Mission"; + case DynamicZoneType::Quest: + return "Quest"; + } + return "Unknown"; +} diff --git a/common/dynamic_zone_base.h b/common/dynamic_zone_base.h index 5a84fa8fa4..bc325532e8 100644 --- a/common/dynamic_zone_base.h +++ b/common/dynamic_zone_base.h @@ -3,6 +3,7 @@ #include "eq_constants.h" #include "repositories/dynamic_zones_repository.h" +#include "repositories/dynamic_zone_members_repository.h" #include #include #include @@ -56,27 +57,42 @@ class DynamicZoneBase DynamicZoneBase(DynamicZoneType type) : m_type(type) {} DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& entry); + static std::string GetDynamicZoneTypeName(DynamicZoneType dz_type); + virtual void SetSecondsRemaining(uint32_t seconds_remaining) = 0; uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); } uint32_t GetID() const { return m_id; } uint16_t GetInstanceID() const { return static_cast(m_instance_id); } uint32_t GetMaxPlayers() const { return m_max_players; } + uint32_t GetMemberCount() const { return static_cast(m_members.size()); } uint32_t GetMinPlayers() const { return m_min_players; } uint32_t GetSecondsRemaining() const; uint16_t GetZoneID() const { return static_cast(m_zone_id); } uint32_t GetZoneIndex() const { return (m_instance_id << 16) | (m_zone_id & 0xffff); } uint32_t GetZoneVersion() const { return m_zone_version; } DynamicZoneType GetType() const { return m_type; } - const std::string& GetLeaderName() const { return m_leader_name; } + const std::string& GetLeaderName() const { return m_leader.name; } const std::string& GetName() const { return m_name; } + const DynamicZoneMember& GetLeader() const { return m_leader; } + const std::vector& GetMembers() const { return m_members; } const DynamicZoneLocation& GetCompassLocation() const { return m_compass; } const DynamicZoneLocation& GetSafeReturnLocation() const { return m_safereturn; } const DynamicZoneLocation& GetZoneInLocation() const { return m_zonein; } std::chrono::system_clock::duration GetDurationRemaining() const { return m_expire_time - std::chrono::system_clock::now(); } void AddCharacter(uint32_t character_id); + void AddInternalMember(const DynamicZoneMember& member); + void AddMemberFromRepositoryResult(DynamicZoneMembersRepository::MemberWithName&& entry); + void ClearInternalMembers() { m_members.clear(); } uint32_t Create(); + uint32_t GetDatabaseMemberCount(); + DynamicZoneMember GetMemberData(uint32_t character_id); + DynamicZoneMember GetMemberData(const std::string& character_name); + bool HasDatabaseMember(uint32_t character_id); + bool HasMember(uint32_t character_id); + bool HasMember(const std::string& character_name); + bool HasMembers() const { return !m_members.empty(); } bool HasZoneInLocation() const { return m_has_zonein; } bool IsExpired() const { return m_expire_time < std::chrono::system_clock::now(); } bool IsInstanceID(uint32_t instance_id) const { return (m_instance_id != 0 && m_instance_id == instance_id); } @@ -84,10 +100,12 @@ class DynamicZoneBase bool IsSameDz(uint32_t zone_id, uint32_t instance_id) const { return zone_id == m_zone_id && instance_id == m_instance_id; } void RemoveAllCharacters(bool enable_removal_timers = true); void RemoveCharacter(uint32_t character_id); - void SaveInstanceMembersToDatabase(const std::vector& character_ids); + void RemoveInternalMember(uint32_t character_id); + void SaveMembers(const std::vector& members); void SetCompass(const DynamicZoneLocation& location, bool update_db = false); void SetCompass(uint32_t zone_id, float x, float y, float z, bool update_db = false); - void SetLeaderName(const std::string& leader_name) { m_leader_name = leader_name; } + bool SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status); + void SetLeader(const DynamicZoneMember& leader) { m_leader = leader; } void SetMaxPlayers(uint32_t max_players) { m_max_players = max_players; } void SetMinPlayers(uint32_t min_players) { m_min_players = min_players; } void SetName(const std::string& name) { m_name = name; } @@ -122,7 +140,7 @@ class DynamicZoneBase bool m_never_expires = false; bool m_has_zonein = false; std::string m_name; - std::string m_leader_name; + DynamicZoneMember m_leader; DynamicZoneType m_type{ DynamicZoneType::None }; DynamicZoneLocation m_compass; DynamicZoneLocation m_safereturn; @@ -130,6 +148,7 @@ class DynamicZoneBase std::chrono::seconds m_duration; std::chrono::time_point m_start_time; std::chrono::time_point m_expire_time; + std::vector m_members; }; #endif diff --git a/common/expedition_base.cpp b/common/expedition_base.cpp index a5f8902040..af961e4a9a 100644 --- a/common/expedition_base.cpp +++ b/common/expedition_base.cpp @@ -1,6 +1,5 @@ #include "expedition_base.h" #include "repositories/expeditions_repository.h" -#include "rulesys.h" ExpeditionBase::ExpeditionBase(uint32_t id, const std::string& uuid, const std::string& expedition_name, const DynamicZoneMember& leader @@ -22,92 +21,3 @@ void ExpeditionBase::LoadRepositoryResult(ExpeditionsRepository::ExpeditionWithL m_leader.id = entry.leader_id; m_leader.name = std::move(entry.leader_name); } - -void ExpeditionBase::AddMemberFromRepositoryResult( - ExpeditionMembersRepository::MemberWithName&& entry) -{ - auto status = DynamicZoneMemberStatus::Unknown; - AddInternalMember({ entry.character_id, std::move(entry.character_name), status }); -} - -void ExpeditionBase::AddInternalMember(const DynamicZoneMember& member) -{ - if (!HasMember(member.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 DynamicZoneMember& member) { return member.id == character_id; } - ), m_members.end()); -} - - -bool ExpeditionBase::HasMember(uint32_t character_id) -{ - return std::any_of(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) { - return member.id == character_id; - }); -} - -bool ExpeditionBase::HasMember(const std::string& character_name) -{ - return std::any_of(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) { - return (strcasecmp(member.name.c_str(), character_name.c_str()) == 0); - }); -} - -DynamicZoneMember ExpeditionBase::GetMemberData(uint32_t character_id) -{ - auto it = std::find_if(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) { - return member.id == character_id; - }); - - DynamicZoneMember member_data; - if (it != m_members.end()) - { - member_data = *it; - } - return member_data; -} - -DynamicZoneMember ExpeditionBase::GetMemberData(const std::string& character_name) -{ - auto it = std::find_if(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) { - return (strcasecmp(member.name.c_str(), character_name.c_str()) == 0); - }); - - DynamicZoneMember member_data; - if (it != m_members.end()) - { - member_data = *it; - } - return member_data; -} - -bool ExpeditionBase::SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status) -{ - if (status == DynamicZoneMemberStatus::InDynamicZone && !RuleB(Expedition, EnableInDynamicZoneStatus)) - { - status = DynamicZoneMemberStatus::Online; - } - - if (character_id == m_leader.id) - { - m_leader.status = status; - } - - auto it = std::find_if(m_members.begin(), m_members.end(), - [&](const DynamicZoneMember& member) { return member.id == character_id; }); - - if (it != m_members.end() && it->status != status) - { - it->status = status; - return true; - } - - return false; -} diff --git a/common/expedition_base.h b/common/expedition_base.h index e93c707b53..cb6f6a591e 100644 --- a/common/expedition_base.h +++ b/common/expedition_base.h @@ -3,10 +3,8 @@ #include "dynamic_zone_base.h" #include "repositories/expeditions_repository.h" -#include "repositories/expedition_members_repository.h" #include #include -#include class ExpeditionBase { @@ -19,38 +17,24 @@ class ExpeditionBase uint32_t GetID() const { return m_id; } uint32_t GetLeaderID() const { return m_leader.id; } - 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 DynamicZoneMember& 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); - bool SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status); + const DynamicZoneMember& GetLeader() const { return m_leader; } 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 DynamicZoneMember& leader); - DynamicZoneMember GetMemberData(uint32_t character_id); - DynamicZoneMember GetMemberData(const std::string& character_name); - uint32_t m_id = 0; bool m_is_locked = false; bool m_add_replay_on_join = true; std::string m_uuid; std::string m_expedition_name; DynamicZoneMember m_leader; - std::vector m_members; }; #endif diff --git a/common/repositories/base/base_expedition_members_repository.h b/common/repositories/base/base_dynamic_zone_members_repository.h similarity index 59% rename from common/repositories/base/base_expedition_members_repository.h rename to common/repositories/base/base_dynamic_zone_members_repository.h index dde0be5881..07fee6723b 100644 --- a/common/repositories/base/base_expedition_members_repository.h +++ b/common/repositories/base/base_dynamic_zone_members_repository.h @@ -4,22 +4,22 @@ * This repository was automatically generated and is NOT to be modified directly. * Any repository modifications are meant to be made to the repository extending the base. * Any modifications to base repositories are to be made by the generator only - * + * * @generator ./utils/scripts/generators/repository-generator.pl * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories */ -#ifndef EQEMU_BASE_EXPEDITION_MEMBERS_REPOSITORY_H -#define EQEMU_BASE_EXPEDITION_MEMBERS_REPOSITORY_H +#ifndef EQEMU_BASE_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H +#define EQEMU_BASE_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H #include "../../database.h" #include "../../string_util.h" -class BaseExpeditionMembersRepository { +class BaseDynamicZoneMembersRepository { public: - struct ExpeditionMembers { + struct DynamicZoneMembers { int id; - int expedition_id; + int dynamic_zone_id; int character_id; int is_current_member; }; @@ -33,7 +33,7 @@ class BaseExpeditionMembersRepository { { return { "id", - "expedition_id", + "dynamic_zone_id", "character_id", "is_current_member", }; @@ -46,7 +46,7 @@ class BaseExpeditionMembersRepository { static std::string TableName() { - return std::string("expedition_members"); + return std::string("dynamic_zone_members"); } static std::string BaseSelect() @@ -67,51 +67,51 @@ class BaseExpeditionMembersRepository { ); } - static ExpeditionMembers NewEntity() + static DynamicZoneMembers NewEntity() { - ExpeditionMembers entry{}; + DynamicZoneMembers entry{}; entry.id = 0; - entry.expedition_id = 0; + entry.dynamic_zone_id = 0; entry.character_id = 0; entry.is_current_member = 1; return entry; } - static ExpeditionMembers GetExpeditionMembersEntry( - const std::vector &expedition_memberss, - int expedition_members_id + static DynamicZoneMembers GetDynamicZoneMembersEntry( + const std::vector &dynamic_zone_memberss, + int dynamic_zone_members_id ) { - for (auto &expedition_members : expedition_memberss) { - if (expedition_members.id == expedition_members_id) { - return expedition_members; + for (auto &dynamic_zone_members : dynamic_zone_memberss) { + if (dynamic_zone_members.id == dynamic_zone_members_id) { + return dynamic_zone_members; } } return NewEntity(); } - static ExpeditionMembers FindOne( + static DynamicZoneMembers FindOne( Database& db, - int expedition_members_id + int dynamic_zone_members_id ) { auto results = db.QueryDatabase( fmt::format( "{} WHERE id = {} LIMIT 1", BaseSelect(), - expedition_members_id + dynamic_zone_members_id ) ); auto row = results.begin(); if (results.RowCount() == 1) { - ExpeditionMembers entry{}; + DynamicZoneMembers entry{}; entry.id = atoi(row[0]); - entry.expedition_id = atoi(row[1]); + entry.dynamic_zone_id = atoi(row[1]); entry.character_id = atoi(row[2]); entry.is_current_member = atoi(row[3]); @@ -123,7 +123,7 @@ class BaseExpeditionMembersRepository { static int DeleteOne( Database& db, - int expedition_members_id + int dynamic_zone_members_id ) { auto results = db.QueryDatabase( @@ -131,7 +131,7 @@ class BaseExpeditionMembersRepository { "DELETE FROM {} WHERE {} = {}", TableName(), PrimaryKey(), - expedition_members_id + dynamic_zone_members_id ) ); @@ -140,16 +140,16 @@ class BaseExpeditionMembersRepository { static int UpdateOne( Database& db, - ExpeditionMembers expedition_members_entry + DynamicZoneMembers dynamic_zone_members_entry ) { std::vector update_values; auto columns = Columns(); - update_values.push_back(columns[1] + " = " + std::to_string(expedition_members_entry.expedition_id)); - update_values.push_back(columns[2] + " = " + std::to_string(expedition_members_entry.character_id)); - update_values.push_back(columns[3] + " = " + std::to_string(expedition_members_entry.is_current_member)); + update_values.push_back(columns[1] + " = " + std::to_string(dynamic_zone_members_entry.dynamic_zone_id)); + update_values.push_back(columns[2] + " = " + std::to_string(dynamic_zone_members_entry.character_id)); + update_values.push_back(columns[3] + " = " + std::to_string(dynamic_zone_members_entry.is_current_member)); auto results = db.QueryDatabase( fmt::format( @@ -157,24 +157,24 @@ class BaseExpeditionMembersRepository { TableName(), implode(", ", update_values), PrimaryKey(), - expedition_members_entry.id + dynamic_zone_members_entry.id ) ); return (results.Success() ? results.RowsAffected() : 0); } - static ExpeditionMembers InsertOne( + static DynamicZoneMembers InsertOne( Database& db, - ExpeditionMembers expedition_members_entry + DynamicZoneMembers dynamic_zone_members_entry ) { std::vector insert_values; - insert_values.push_back(std::to_string(expedition_members_entry.id)); - insert_values.push_back(std::to_string(expedition_members_entry.expedition_id)); - insert_values.push_back(std::to_string(expedition_members_entry.character_id)); - insert_values.push_back(std::to_string(expedition_members_entry.is_current_member)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.id)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.dynamic_zone_id)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.character_id)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.is_current_member)); auto results = db.QueryDatabase( fmt::format( @@ -185,29 +185,29 @@ class BaseExpeditionMembersRepository { ); if (results.Success()) { - expedition_members_entry.id = results.LastInsertedID(); - return expedition_members_entry; + dynamic_zone_members_entry.id = results.LastInsertedID(); + return dynamic_zone_members_entry; } - expedition_members_entry = NewEntity(); + dynamic_zone_members_entry = NewEntity(); - return expedition_members_entry; + return dynamic_zone_members_entry; } static int InsertMany( Database& db, - std::vector expedition_members_entries + std::vector dynamic_zone_members_entries ) { std::vector insert_chunks; - for (auto &expedition_members_entry: expedition_members_entries) { + for (auto &dynamic_zone_members_entry: dynamic_zone_members_entries) { std::vector insert_values; - insert_values.push_back(std::to_string(expedition_members_entry.id)); - insert_values.push_back(std::to_string(expedition_members_entry.expedition_id)); - insert_values.push_back(std::to_string(expedition_members_entry.character_id)); - insert_values.push_back(std::to_string(expedition_members_entry.is_current_member)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.id)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.dynamic_zone_id)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.character_id)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.is_current_member)); insert_chunks.push_back("(" + implode(",", insert_values) + ")"); } @@ -225,9 +225,9 @@ class BaseExpeditionMembersRepository { return (results.Success() ? results.RowsAffected() : 0); } - static std::vector All(Database& db) + static std::vector All(Database& db) { - std::vector all_entries; + std::vector all_entries; auto results = db.QueryDatabase( fmt::format( @@ -239,10 +239,10 @@ class BaseExpeditionMembersRepository { all_entries.reserve(results.RowCount()); for (auto row = results.begin(); row != results.end(); ++row) { - ExpeditionMembers entry{}; + DynamicZoneMembers entry{}; entry.id = atoi(row[0]); - entry.expedition_id = atoi(row[1]); + entry.dynamic_zone_id = atoi(row[1]); entry.character_id = atoi(row[2]); entry.is_current_member = atoi(row[3]); @@ -252,9 +252,9 @@ class BaseExpeditionMembersRepository { return all_entries; } - static std::vector GetWhere(Database& db, std::string where_filter) + static std::vector GetWhere(Database& db, std::string where_filter) { - std::vector all_entries; + std::vector all_entries; auto results = db.QueryDatabase( fmt::format( @@ -267,10 +267,10 @@ class BaseExpeditionMembersRepository { all_entries.reserve(results.RowCount()); for (auto row = results.begin(); row != results.end(); ++row) { - ExpeditionMembers entry{}; + DynamicZoneMembers entry{}; entry.id = atoi(row[0]); - entry.expedition_id = atoi(row[1]); + entry.dynamic_zone_id = atoi(row[1]); entry.character_id = atoi(row[2]); entry.is_current_member = atoi(row[3]); @@ -307,4 +307,4 @@ class BaseExpeditionMembersRepository { }; -#endif //EQEMU_BASE_EXPEDITION_MEMBERS_REPOSITORY_H +#endif //EQEMU_BASE_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H diff --git a/common/repositories/dynamic_zone_members_repository.h b/common/repositories/dynamic_zone_members_repository.h new file mode 100644 index 0000000000..2392b09654 --- /dev/null +++ b/common/repositories/dynamic_zone_members_repository.h @@ -0,0 +1,249 @@ +/** + * EQEmulator: Everquest Server Emulator + * Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server) + * + * 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 EQEMU_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H +#define EQEMU_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H + +#include "../database.h" +#include "../string_util.h" +#include "base/base_dynamic_zone_members_repository.h" + +class DynamicZoneMembersRepository: public BaseDynamicZoneMembersRepository { +public: + + /** + * This file was auto generated and can be modified and extended upon + * + * Base repository methods are automatically + * generated in the "base" version of this repository. The base repository + * is immutable and to be left untouched, while methods in this class + * are used as extension methods for more specific persistence-layer + * accessors or mutators. + * + * Base Methods (Subject to be expanded upon in time) + * + * Note: Not all tables are designed appropriately to fit functionality with all base methods + * + * InsertOne + * UpdateOne + * DeleteOne + * FindOne + * GetWhere(std::string where_filter) + * DeleteWhere(std::string where_filter) + * InsertMany + * All + * + * Example custom methods in a repository + * + * DynamicZoneMembersRepository::GetByZoneAndVersion(int zone_id, int zone_version) + * DynamicZoneMembersRepository::GetWhereNeverExpires() + * DynamicZoneMembersRepository::GetWhereXAndY() + * DynamicZoneMembersRepository::DeleteWhereXAndY() + * + * Most of the above could be covered by base methods, but if you as a developer + * find yourself re-using logic for other parts of the code, its best to just make a + * method that can be re-used easily elsewhere especially if it can use a base repository + * method and encapsulate filters there + */ + + // Custom extended repository methods here + + struct MemberWithName { + uint32_t id; + uint32_t dynamic_zone_id; + uint32_t character_id; + int is_current_member; + std::string character_name; + }; + + static std::string SelectMembersWithNames() + { + return std::string(SQL( + SELECT + dynamic_zone_members.id, + dynamic_zone_members.dynamic_zone_id, + dynamic_zone_members.character_id, + dynamic_zone_members.is_current_member, + character_data.name + FROM dynamic_zone_members + INNER JOIN character_data ON dynamic_zone_members.character_id = character_data.id + )); + } + + static std::vector GetWithNames(Database& db, + const std::vector& dynamic_zone_ids) + { + if (dynamic_zone_ids.empty()) + { + return {}; + } + + std::vector all_entries; + + auto results = db.QueryDatabase(fmt::format(SQL( + {} + WHERE dynamic_zone_members.dynamic_zone_id IN ({}) + AND dynamic_zone_members.is_current_member = TRUE; + ), + SelectMembersWithNames(), + fmt::join(dynamic_zone_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.dynamic_zone_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; + } + + static int DeleteByInstance(Database& db, int instance_id) + { + auto results = db.QueryDatabase(fmt::format(SQL( + DELETE dynamic_zone_members + FROM dynamic_zone_members + INNER JOIN dynamic_zones ON dynamic_zone_members.dynamic_zone_id = dynamic_zones.id + WHERE dynamic_zones.instance_id = {} + ), instance_id)); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int DeleteByManyInstances(Database& db, const std::string& joined_instance_ids) + { + auto results = db.QueryDatabase(fmt::format(SQL( + DELETE dynamic_zone_members + FROM dynamic_zone_members + INNER JOIN dynamic_zones ON dynamic_zone_members.dynamic_zone_id = dynamic_zones.id + WHERE dynamic_zones.instance_id IN ({}) + ), joined_instance_ids)); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int GetCountWhere(Database& db, const std::string& where_filter) + { + auto results = db.QueryDatabase(fmt::format( + "SELECT COUNT(*) FROM {} WHERE {};", TableName(), where_filter)); + + uint32_t count = 0; + if (results.Success() && results.RowCount() > 0) + { + auto row = results.begin(); + count = strtoul(row[0], nullptr, 10); + } + return count; + } + + static void AddMember(Database& db, uint32_t dynamic_zone_id, uint32_t character_id) + { + db.QueryDatabase(fmt::format(SQL( + INSERT INTO {} + (dynamic_zone_id, character_id) + VALUES + ({}, {}) + ON DUPLICATE KEY UPDATE is_current_member = TRUE; + ), + TableName(), + dynamic_zone_id, + character_id + )); + } + + static void RemoveMember(Database& db, uint32_t dynamic_zone_id, uint32_t character_id) + { + db.QueryDatabase(fmt::format(SQL( + UPDATE {} SET is_current_member = FALSE + WHERE dynamic_zone_id = {} AND character_id = {}; + ), + TableName(), dynamic_zone_id, character_id + )); + } + + static void RemoveAllMembers(Database& db, uint32_t dynamic_zone_id) + { + db.QueryDatabase(fmt::format(SQL( + UPDATE {} SET is_current_member = FALSE + WHERE dynamic_zone_id = {}; + ), + TableName(), dynamic_zone_id + )); + } + + static void RemoveAllMembers(Database& db, std::vector dynamic_zone_ids) + { + if (!dynamic_zone_ids.empty()) + { + db.QueryDatabase(fmt::format(SQL( + UPDATE {} SET is_current_member = FALSE + WHERE dynamic_zone_id IN ({}); + ), + TableName(), fmt::join(dynamic_zone_ids, ",") + )); + } + } + + static int InsertOrUpdateMany(Database& db, + const std::vector& dynamic_zone_members_entries) + { + std::vector insert_chunks; + + for (auto &dynamic_zone_members_entry: dynamic_zone_members_entries) + { + std::vector insert_values; + + insert_values.push_back(std::to_string(dynamic_zone_members_entry.id)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.dynamic_zone_id)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.character_id)); + insert_values.push_back(std::to_string(dynamic_zone_members_entry.is_current_member)); + + insert_chunks.push_back("(" + implode(",", insert_values) + ")"); + } + + std::vector insert_values; + + auto results = db.QueryDatabase( + fmt::format( + "INSERT INTO {} ({}) VALUES {} ON DUPLICATE KEY UPDATE is_current_member = TRUE;", + TableName(), + ColumnsRaw(), + implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } +}; + +#endif //EQEMU_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H diff --git a/common/repositories/dynamic_zones_repository.h b/common/repositories/dynamic_zones_repository.h index 27fd406ca1..24d944209b 100644 --- a/common/repositories/dynamic_zones_repository.h +++ b/common/repositories/dynamic_zones_repository.h @@ -249,7 +249,7 @@ class DynamicZonesRepository: public BaseDynamicZonesRepository { int version; uint32_t start_time; int duration; - int player_count; + int member_count; }; static std::string SelectDynamicZoneInstancePlayerCount() @@ -263,10 +263,11 @@ class DynamicZonesRepository: public BaseDynamicZonesRepository { instance_list.version, instance_list.start_time, instance_list.duration, - COUNT(instance_list_player.id) member_count + COUNT(dynamic_zone_members.character_id) member_count FROM dynamic_zones INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id - LEFT JOIN instance_list_player ON instance_list.id = instance_list_player.id + LEFT JOIN dynamic_zone_members ON dynamic_zones.id = dynamic_zone_members.dynamic_zone_id + AND dynamic_zone_members.is_current_member = TRUE GROUP BY instance_list.id ORDER BY dynamic_zones.id; )); @@ -293,7 +294,7 @@ class DynamicZonesRepository: public BaseDynamicZonesRepository { entry.version = strtol(row[col++], nullptr, 10); entry.start_time = strtoul(row[col++], nullptr, 10); entry.duration = strtol(row[col++], nullptr, 10); - entry.player_count = strtol(row[col++], nullptr, 10); + entry.member_count = strtol(row[col++], nullptr, 10); all_entries.emplace_back(std::move(entry)); } diff --git a/common/repositories/expedition_members_repository.h b/common/repositories/expedition_members_repository.h deleted file mode 100644 index 55b5bddd7f..0000000000 --- a/common/repositories/expedition_members_repository.h +++ /dev/null @@ -1,132 +0,0 @@ -/** - * EQEmulator: Everquest Server Emulator - * Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server) - * - * 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 EQEMU_EXPEDITION_MEMBERS_REPOSITORY_H -#define EQEMU_EXPEDITION_MEMBERS_REPOSITORY_H - -#include "../database.h" -#include "../string_util.h" -#include "base/base_expedition_members_repository.h" - -class ExpeditionMembersRepository: public BaseExpeditionMembersRepository { -public: - - /** - * This file was auto generated and can be modified and extended upon - * - * Base repository methods are automatically - * generated in the "base" version of this repository. The base repository - * is immutable and to be left untouched, while methods in this class - * are used as extension methods for more specific persistence-layer - * accessors or mutators. - * - * Base Methods (Subject to be expanded upon in time) - * - * Note: Not all tables are designed appropriately to fit functionality with all base methods - * - * InsertOne - * UpdateOne - * DeleteOne - * FindOne - * GetWhere(std::string where_filter) - * DeleteWhere(std::string where_filter) - * InsertMany - * All - * - * Example custom methods in a repository - * - * ExpeditionMembersRepository::GetByZoneAndVersion(int zone_id, int zone_version) - * ExpeditionMembersRepository::GetWhereNeverExpires() - * ExpeditionMembersRepository::GetWhereXAndY() - * ExpeditionMembersRepository::DeleteWhereXAndY() - * - * Most of the above could be covered by base methods, but if you as a developer - * find yourself re-using logic for other parts of the code, its best to just make a - * method that can be re-used easily elsewhere especially if it can use a base repository - * method and encapsulate filters there - */ - - // 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 47c8210606..654b676b02 100644 --- a/common/repositories/expeditions_repository.h +++ b/common/repositories/expeditions_repository.h @@ -184,11 +184,11 @@ class ExpeditionsRepository: public BaseExpeditionsRepository { character_data.name, MAX(expeditions.id) FROM character_data - LEFT JOIN expedition_members - ON character_data.id = expedition_members.character_id - AND expedition_members.is_current_member = TRUE + LEFT JOIN dynamic_zone_members + ON character_data.id = dynamic_zone_members.character_id + AND dynamic_zone_members.is_current_member = TRUE LEFT JOIN expeditions - ON expedition_members.expedition_id = expeditions.id + ON dynamic_zone_members.dynamic_zone_id = expeditions.dynamic_zone_id WHERE character_data.name IN ({}) GROUP BY character_data.id ORDER BY FIELD(character_data.name, {}) @@ -214,6 +214,37 @@ class ExpeditionsRepository: public BaseExpeditionsRepository { return entries; } + + static uint32_t GetIDByMemberID(Database& db, uint32_t character_id) + { + if (character_id == 0) + { + return 0; + } + + uint32_t expedition_id = 0; + + auto results = db.QueryDatabase(fmt::format(SQL( + SELECT + expeditions.id + FROM expeditions + INNER JOIN dynamic_zone_members + ON expeditions.dynamic_zone_id = dynamic_zone_members.dynamic_zone_id + WHERE + dynamic_zone_members.character_id = {} + AND dynamic_zone_members.is_current_member = TRUE; + ), + character_id + )); + + if (results.Success() && results.RowCount() > 0) + { + auto row = results.begin(); + expedition_id = std::strtoul(row[0], nullptr, 10); + } + + return expedition_id; + } }; #endif //EQEMU_EXPEDITIONS_REPOSITORY_H diff --git a/common/repositories/instance_list_player_repository.h b/common/repositories/instance_list_player_repository.h index f865e5fd8b..3a526a73e8 100644 --- a/common/repositories/instance_list_player_repository.h +++ b/common/repositories/instance_list_player_repository.h @@ -65,6 +65,34 @@ class InstanceListPlayerRepository: public BaseInstanceListPlayerRepository { // Custom extended repository methods here + static int InsertOrUpdateMany(Database& db, + const std::vector& instance_list_player_entries) + { + std::vector insert_chunks; + + for (auto &instance_list_player_entry: instance_list_player_entries) + { + std::vector insert_values; + + insert_values.push_back(std::to_string(instance_list_player_entry.id)); + insert_values.push_back(std::to_string(instance_list_player_entry.charid)); + + insert_chunks.push_back("(" + implode(",", insert_values) + ")"); + } + + std::vector insert_values; + + auto results = db.QueryDatabase( + fmt::format( + "INSERT INTO {} ({}) VALUES {} ON DUPLICATE KEY UPDATE id = VALUES(id)", + TableName(), + ColumnsRaw(), + implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_INSTANCE_LIST_PLAYER_REPOSITORY_H diff --git a/common/ruletypes.h b/common/ruletypes.h index 5a30bfc2ca..1d84a3b6ba 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -741,7 +741,6 @@ RULE_CATEGORY(Expedition) RULE_INT(Expedition, MinStatusToBypassPlayerCountRequirements, 80, "Minimum GM status to bypass minimum player requirements for Expedition creation") RULE_BOOL(Expedition, AlwaysNotifyNewLeaderOnChange, false, "Always notify clients when made expedition leader. If false (live-like) new leaders are only notified when made leader via /dzmakeleader") RULE_REAL(Expedition, LockoutDurationMultiplier, 1.0, "Multiplies lockout duration by this value when new lockouts are added") -RULE_BOOL(Expedition, EnableInDynamicZoneStatus, false, "Enables the 'In Dynamic Zone' member status in expedition window. If false (live-like) players inside the dynamic zone will show as 'Online'") RULE_INT(Expedition, ChooseLeaderCooldownTime, 2000, "Cooldown time (milliseconds) between choosing a new leader for automatic leader changes") RULE_CATEGORY_END() @@ -749,6 +748,7 @@ RULE_CATEGORY(DynamicZone) RULE_INT(DynamicZone, ClientRemovalDelayMS, 60000, "Delay (milliseconds) until a client is teleported out of dynamic zone after being removed as member") RULE_BOOL(DynamicZone, EmptyShutdownEnabled, true, "Enable early instance shutdown for dynamic zones that have no members") RULE_INT(DynamicZone, EmptyShutdownDelaySeconds, 1500, "Seconds to set dynamic zone instance expiration if early shutdown enabled") +RULE_BOOL(DynamicZone, EnableInDynamicZoneStatus, false, "Enables the 'In Dynamic Zone' member status in dynamic zone window. If false (live-like) players inside the dynamic zone will show as 'Online'") RULE_INT(DynamicZone, WorldProcessRate, 6000, "Timer interval (milliseconds) that systems check their dynamic zone states") RULE_CATEGORY_END() diff --git a/common/version.h b/common/version.h index af6a207e52..70bb6c410d 100644 --- a/common/version.h +++ b/common/version.h @@ -34,7 +34,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9165 +#define CURRENT_BINARY_DATABASE_VERSION 9166 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9027 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 55c8facd77..8efa47aa97 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -419,6 +419,7 @@ 9163|2021_04_17_zone_safe_heading_changes.sql|SHOW COLUMNS FROM `zone` LIKE 'safe_heading'|empty| 9164|2021_04_23_character_exp_modifiers.sql|SHOW TABLES LIKE 'character_exp_modifiers'|empty| 9165|2021_04_28_idle_pathing.sql|SHOW COLUMNS FROM `spawn2` LIKE 'path_when_zone_idle'|empty| +9166|2021_02_12_dynamic_zone_members.sql|SHOW TABLES LIKE 'dynamic_zone_members'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2021_02_12_dynamic_zone_members.sql b/utils/sql/git/required/2021_02_12_dynamic_zone_members.sql new file mode 100644 index 0000000000..767f650129 --- /dev/null +++ b/utils/sql/git/required/2021_02_12_dynamic_zone_members.sql @@ -0,0 +1,11 @@ +CREATE TABLE `dynamic_zone_members` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `dynamic_zone_id` int(10) unsigned NOT NULL DEFAULT 0, + `character_id` int(10) unsigned NOT NULL DEFAULT 0, + `is_current_member` tinyint(3) unsigned NOT NULL DEFAULT 1, + PRIMARY KEY (`id`), + UNIQUE KEY `dynamic_zone_id_character_id` (`dynamic_zone_id`,`character_id`), + KEY `character_id` (`character_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +DROP TABLE `expedition_members`; diff --git a/world/dynamic_zone.cpp b/world/dynamic_zone.cpp index dad35db820..943ea83a95 100644 --- a/world/dynamic_zone.cpp +++ b/world/dynamic_zone.cpp @@ -25,11 +25,12 @@ DynamicZone* DynamicZone::FindDynamicZoneByID(uint32_t dz_id) return nullptr; } -DynamicZoneStatus DynamicZone::Process(bool force_expire) +DynamicZoneStatus DynamicZone::Process() { DynamicZoneStatus status = DynamicZoneStatus::Normal; - if (force_expire || IsExpired()) + // force expire if no members + if (!HasMembers() || IsExpired()) { status = DynamicZoneStatus::Expired; @@ -38,7 +39,7 @@ DynamicZoneStatus DynamicZone::Process(bool force_expire) { status = DynamicZoneStatus::ExpiredEmpty; - if (force_expire && !m_is_pending_early_shutdown && RuleB(DynamicZone, EmptyShutdownEnabled)) + if (!HasMembers() && !m_is_pending_early_shutdown && RuleB(DynamicZone, EmptyShutdownEnabled)) { SetSecondsRemaining(RuleI(DynamicZone, EmptyShutdownDelaySeconds)); m_is_pending_early_shutdown = true; diff --git a/world/dynamic_zone.h b/world/dynamic_zone.h index 60eb5b65a2..597604f627 100644 --- a/world/dynamic_zone.h +++ b/world/dynamic_zone.h @@ -24,7 +24,7 @@ class DynamicZone : public DynamicZoneBase void SetSecondsRemaining(uint32_t seconds_remaining) override; - DynamicZoneStatus Process(bool force_expire); + DynamicZoneStatus Process(); protected: Database& GetDatabase() override; diff --git a/world/expedition.cpp b/world/expedition.cpp index a68ddd093c..4b29e4f0ac 100644 --- a/world/expedition.cpp +++ b/world/expedition.cpp @@ -39,14 +39,14 @@ Expedition::Expedition() : void Expedition::SetDynamicZone(DynamicZone&& dz) { dz.SetName(GetName()); - dz.SetLeaderName(GetLeaderName()); + dz.SetLeader(GetLeader()); m_dynamic_zone = std::move(dz); } void Expedition::RemoveMember(uint32_t character_id) { - RemoveInternalMember(character_id); + GetDynamicZone().RemoveInternalMember(character_id); if (character_id == m_leader.id) { @@ -56,13 +56,14 @@ void Expedition::RemoveMember(uint32_t character_id) void Expedition::ChooseNewLeader() { - if (m_members.empty() || !m_choose_leader_cooldown_timer.Check()) + const auto& members = GetDynamicZone().GetMembers(); + if (members.empty() || !m_choose_leader_cooldown_timer.Check()) { m_choose_leader_needed = true; return; } - auto it = std::find_if(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) { + auto it = std::find_if(members.begin(), members.end(), [&](const DynamicZoneMember& member) { if (member.id != m_leader.id && member.IsOnline()) { auto member_cle = client_list.FindCLEByCharacterID(member.id); return (member_cle && member_cle->GetOnline() == CLE_Status::InZone); @@ -70,14 +71,14 @@ void Expedition::ChooseNewLeader() return false; }); - if (it == m_members.end()) + if (it == members.end()) { // no online members found, fallback to choosing any member - it = std::find_if(m_members.begin(), m_members.end(), + it = std::find_if(members.begin(), members.end(), [&](const DynamicZoneMember& member) { return (member.id != m_leader.id); }); } - if (it != m_members.end() && SetNewLeader(*it)) + if (it != members.end() && SetNewLeader(*it)) { m_choose_leader_needed = false; } @@ -85,7 +86,7 @@ void Expedition::ChooseNewLeader() bool Expedition::SetNewLeader(const DynamicZoneMember& member) { - if (!HasMember(member.id)) + if (!GetDynamicZone().HasMember(member.id)) { return false; } @@ -93,7 +94,7 @@ bool Expedition::SetNewLeader(const DynamicZoneMember& member) LogExpeditionsModerate("Replacing [{}] leader [{}] with [{}]", m_id, m_leader.name, member.name); ExpeditionDatabase::UpdateLeaderID(m_id, member.id); m_leader = member; - m_dynamic_zone.SetLeaderName(m_leader.name); + m_dynamic_zone.SetLeader(m_leader); SendZonesLeaderChanged(); return true; } @@ -156,7 +157,7 @@ bool Expedition::Process() { // returns true if expedition needs to be deleted from world cache and db // expedition is not deleted until its dz has no clients to prevent exploits - auto status = m_dynamic_zone.Process(IsEmpty()); // force expire if no members + auto status = m_dynamic_zone.Process(); if (status == DynamicZoneStatus::ExpiredEmpty) { LogExpeditions("Expedition [{}] expired or empty, notifying zones and deleting", GetID()); @@ -172,7 +173,13 @@ bool Expedition::Process() void Expedition::UpdateMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status) { - SetInternalMemberStatus(character_id, status); + GetDynamicZone().SetInternalMemberStatus(character_id, status); + + // temporary until move to using dz leader object completely + if (character_id == m_leader.id) + { + m_leader.status = GetDynamicZone().GetLeader().status; + } // any member status update will trigger a leader fix if leader was offline if (m_leader.status == DynamicZoneMemberStatus::Offline) @@ -183,7 +190,7 @@ void Expedition::UpdateMemberStatus(uint32_t character_id, DynamicZoneMemberStat void Expedition::SendZoneMemberStatuses(uint16_t zone_id, uint16_t instance_id) { - const auto& members = GetMembers(); + const auto& members = GetDynamicZone().GetMembers(); uint32_t members_count = static_cast(members.size()); uint32_t entries_size = sizeof(ServerExpeditionMemberStatusEntry_Struct) * members_count; @@ -210,7 +217,7 @@ void Expedition::CacheMemberStatuses() all_clients.reserve(client_list.GetClientCount()); client_list.GetClients(zone_name.c_str(), all_clients); - for (const auto& member : m_members) + for (const auto& member : GetDynamicZone().GetMembers()) { auto it = std::find_if(all_clients.begin(), all_clients.end(), [&](const ClientListEntry* cle) { return (cle && cle->CharID() == member.id); }); @@ -225,6 +232,6 @@ void Expedition::CacheMemberStatuses() } } - SetInternalMemberStatus(member.id, status); + GetDynamicZone().SetInternalMemberStatus(member.id, status); } } diff --git a/world/expedition_database.cpp b/world/expedition_database.cpp index c3738901ae..5c51a9e705 100644 --- a/world/expedition_database.cpp +++ b/world/expedition_database.cpp @@ -21,26 +21,28 @@ #include "expedition_database.h" #include "expedition.h" #include "worlddb.h" +#include "../common/repositories/dynamic_zone_members_repository.h" void ExpeditionDatabase::PurgeExpiredExpeditions() { std::string query = SQL( SELECT - expeditions.id + expeditions.id, + expeditions.dynamic_zone_id FROM expeditions LEFT JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id LEFT JOIN instance_list ON dynamic_zones.instance_id = instance_list.id LEFT JOIN ( - SELECT expedition_id, COUNT(IF(is_current_member = TRUE, 1, NULL)) member_count - FROM expedition_members - GROUP BY expedition_id - ) expedition_members - ON expedition_members.expedition_id = expeditions.id + SELECT dynamic_zone_id, COUNT(IF(is_current_member = TRUE, 1, NULL)) member_count + FROM dynamic_zone_members + GROUP BY dynamic_zone_id + ) dynamic_zone_members + ON dynamic_zone_members.dynamic_zone_id = expeditions.dynamic_zone_id WHERE instance_list.id IS NULL - OR expedition_members.member_count IS NULL - OR expedition_members.member_count = 0 + OR dynamic_zone_members.member_count IS NULL + OR dynamic_zone_members.member_count = 0 OR (instance_list.start_time + instance_list.duration) <= UNIX_TIMESTAMP(); ); @@ -48,15 +50,18 @@ void ExpeditionDatabase::PurgeExpiredExpeditions() if (results.Success()) { std::vector expedition_ids; + std::vector dynamic_zone_ids; for (auto row = results.begin(); row != results.end(); ++row) { expedition_ids.emplace_back(static_cast(strtoul(row[0], nullptr, 10))); + dynamic_zone_ids.emplace_back(static_cast(strtoul(row[1], nullptr, 10))); } if (!expedition_ids.empty()) { ExpeditionDatabase::MoveMembersToSafeReturn(expedition_ids); ExpeditionDatabase::DeleteExpeditions(expedition_ids); + DynamicZoneMembersRepository::RemoveAllMembers(database, dynamic_zone_ids); } } } @@ -82,9 +87,6 @@ void ExpeditionDatabase::DeleteExpeditions(const std::vector& expediti auto query = fmt::format("DELETE FROM expeditions WHERE id IN ({});", expedition_ids_query); database.QueryDatabase(query); - query = fmt::format("DELETE FROM expedition_members WHERE expedition_id IN ({});", expedition_ids_query); - database.QueryDatabase(query); - query = fmt::format("DELETE FROM expedition_lockouts WHERE expedition_id IN ({});", expedition_ids_query); database.QueryDatabase(query); } @@ -108,8 +110,8 @@ void ExpeditionDatabase::MoveMembersToSafeReturn(const std::vector& ex // only offline members still in expired dz zones should be updated here std::string query = fmt::format(SQL( UPDATE character_data - INNER JOIN expedition_members ON character_data.id = expedition_members.character_id - INNER JOIN expeditions ON expedition_members.expedition_id = expeditions.id + INNER JOIN dynamic_zone_members ON character_data.id = dynamic_zone_members.character_id + INNER JOIN expeditions ON dynamic_zone_members.dynamic_zone_id = expeditions.dynamic_zone_id INNER JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id AND character_data.zone_instance = instance_list.id diff --git a/world/expedition_state.cpp b/world/expedition_state.cpp index 8f3b6b423a..a0cd245fa2 100644 --- a/world/expedition_state.cpp +++ b/world/expedition_state.cpp @@ -22,8 +22,9 @@ #include "expedition.h" #include "expedition_database.h" #include "worlddb.h" +#include "../common/dynamic_zone_base.h" #include "../common/eqemu_logsys.h" -#include "../common/repositories/expedition_members_repository.h" +#include "../common/repositories/dynamic_zone_members_repository.h" #include ExpeditionState expedition_state; @@ -76,16 +77,14 @@ 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) { - 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); + auto dynamic_zone_members = DynamicZoneMembersRepository::GetWithNames(database, dynamic_zone_ids); for (auto& entry : expedition_entries) { @@ -102,11 +101,11 @@ void ExpeditionState::CacheExpeditions( expedition->SetDynamicZone(std::move(*dz_entry_iter)); } - for (auto& member : expedition_members) + for (auto& member : dynamic_zone_members) { - if (member.expedition_id == expedition->GetID()) + if (member.dynamic_zone_id == entry.dynamic_zone_id) { - expedition->AddMemberFromRepositoryResult(std::move(member)); + expedition->GetDynamicZone().AddMemberFromRepositoryResult(std::move(member)); } } @@ -129,7 +128,7 @@ void ExpeditionState::MemberChange( if (remove) { expedition->RemoveMember(member.id); } else { - expedition->AddInternalMember(member); + expedition->GetDynamicZone().AddInternalMember(member); } } } @@ -139,7 +138,7 @@ void ExpeditionState::RemoveAllMembers(uint32_t expedition_id) auto expedition = GetExpedition(expedition_id); if (expedition) { - expedition->ClearInternalMembers(); + expedition->GetDynamicZone().ClearInternalMembers(); } } @@ -151,6 +150,7 @@ void ExpeditionState::Process() } std::vector expedition_ids; + std::vector dynamic_zone_ids; for (auto it = m_expeditions.begin(); it != m_expeditions.end();) { @@ -158,6 +158,7 @@ void ExpeditionState::Process() if (is_deleted) { expedition_ids.emplace_back((*it)->GetID()); + dynamic_zone_ids.emplace_back((*it)->GetDynamicZone().GetID()); } it = is_deleted ? m_expeditions.erase(it) : it + 1; } @@ -166,5 +167,6 @@ void ExpeditionState::Process() { ExpeditionDatabase::MoveMembersToSafeReturn(expedition_ids); ExpeditionDatabase::DeleteExpeditions(expedition_ids); + DynamicZoneMembersRepository::RemoveAllMembers(database, dynamic_zone_ids); } } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 0a67550f6e..2125b82166 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1717,7 +1717,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) /* Task Packets */ LoadClientTaskState(); - m_expedition_id = ExpeditionDatabase::GetExpeditionIDFromCharacterID(CharacterID()); + m_expedition_id = ExpeditionsRepository::GetIDByMemberID(database, CharacterID()); /** * DevTools Load Settings diff --git a/zone/command.cpp b/zone/command.cpp index 20cb4856f8..3eaea3ccaf 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -6916,7 +6916,7 @@ void command_dz(Client* c, const Seperator* sep) expedition->GetDynamicZone().GetZoneID(), expedition->GetDynamicZone().GetInstanceID(), expedition->GetDynamicZone().GetZoneVersion(), - expedition->GetMemberCount(), + expedition->GetDynamicZone().GetMemberCount(), seconds / 3600, // hours (seconds / 60) % 60, // minutes seconds % 60 // seconds @@ -6982,12 +6982,12 @@ void command_dz(Client* c, const Seperator* sep) c->Message(Chat::White, fmt::format( "dz id: [{}] type: [{}] {}: [{}]:[{}]:[{}] members: [{}] remaining: [{:02}:{:02}:{:02}]", dz.id, - dz.type, + DynamicZone::GetDynamicZoneTypeName(static_cast(dz.type)), zone_saylink, dz.zone, dz.instance, dz.version, - dz.player_count, + dz.member_count, seconds / 3600, // hours (seconds / 60) % 60, // minutes seconds % 60 // seconds diff --git a/zone/expedition.cpp b/zone/expedition.cpp index cb6fa4199d..6b04651625 100644 --- a/zone/expedition.cpp +++ b/zone/expedition.cpp @@ -27,8 +27,8 @@ #include "zonedb.h" #include "../common/eqemu_logsys.h" #include "../common/expedition_lockout_timer.h" +#include "../common/repositories/dynamic_zone_members_repository.h" #include "../common/repositories/expedition_lockouts_repository.h" -#include "../common/repositories/expedition_members_repository.h" #include "../common/util/uuid.h" extern WorldServer worldserver; @@ -59,7 +59,7 @@ Expedition::Expedition( void Expedition::SetDynamicZone(DynamicZone&& dz) { dz.SetName(GetName()); - dz.SetLeaderName(GetLeaderName()); + dz.SetLeader(GetLeader()); m_dynamiczone = std::move(dz); m_dynamiczone.RegisterOnCompassChange([this]() { SendCompassUpdateToZoneMembers(); }); @@ -125,7 +125,7 @@ Expedition* Expedition::TryCreate( expedition->GetDynamicZone().GetMaxPlayers() ); - expedition->SaveMembers(request); + expedition->GetDynamicZone().SaveMembers(request.GetMembers()); expedition->SaveLockouts(request); auto inserted = zone->expedition_cache.emplace(expedition_id, std::move(expedition)); @@ -165,7 +165,7 @@ void Expedition::CacheExpeditions( } auto dynamic_zones = DynamicZonesRepository::GetWithInstance(database, dynamic_zone_ids); - auto expedition_members = ExpeditionMembersRepository::GetWithNames(database, expedition_ids); + auto dynamic_zone_members = DynamicZoneMembersRepository::GetWithNames(database, dynamic_zone_ids); auto expedition_lockouts = ExpeditionLockoutsRepository::GetWithTimestamp(database, expedition_ids); for (auto& entry : expedition_entries) @@ -183,11 +183,11 @@ void Expedition::CacheExpeditions( expedition->SetDynamicZone(std::move(*dz_entry_iter)); } - for (auto& member : expedition_members) + for (auto& member : dynamic_zone_members) { - if (member.expedition_id == expedition->GetID()) + if (member.dynamic_zone_id == entry.dynamic_zone_id) { - expedition->AddMemberFromRepositoryResult(std::move(member)); + expedition->GetDynamicZone().AddMemberFromRepositoryResult(std::move(member)); } } @@ -258,27 +258,13 @@ void Expedition::SaveLockouts(ExpeditionRequest& request) ExpeditionDatabase::InsertLockouts(m_id, m_lockouts); } -void Expedition::SaveMembers(ExpeditionRequest& request) -{ - m_members = request.GetMembers(); - - std::vector member_ids; - for (const auto& member : m_members) - { - member_ids.emplace_back(member.id); - } - - ExpeditionDatabase::InsertMembers(m_id, m_members); - m_dynamiczone.SaveInstanceMembersToDatabase(member_ids); -} - Expedition* Expedition::FindCachedExpeditionByCharacterID(uint32_t character_id) { if (zone) { for (const auto& expedition : zone->expedition_cache) { - if (expedition.second->HasMember(character_id)) + if (expedition.second->GetDynamicZone().HasMember(character_id)) { return expedition.second.get(); } @@ -293,7 +279,7 @@ Expedition* Expedition::FindCachedExpeditionByCharacterName(const std::string& c { for (const auto& expedition : zone->expedition_cache) { - if (expedition.second->HasMember(char_name)) + if (expedition.second->GetDynamicZone().HasMember(char_name)) { return expedition.second.get(); } @@ -384,7 +370,7 @@ void Expedition::AddLockout(const ExpeditionLockoutTimer& lockout, bool members_ { ExpeditionDatabase::InsertLockout(m_id, lockout); } - ExpeditionDatabase::InsertMembersLockout(m_members, lockout); + ExpeditionDatabase::InsertMembersLockout(GetDynamicZone().GetMembers(), lockout); ProcessLockoutUpdate(lockout, false, members_only); SendWorldLockoutUpdate(lockout, false, members_only); @@ -414,7 +400,7 @@ void Expedition::AddLockoutDuration(const std::string& event_name, int seconds, // processing lockout duration applies multiplier again in client methods, // update database with modified value now but pass original on int modified_seconds = static_cast(seconds * RuleR(Expedition, LockoutDurationMultiplier)); - ExpeditionDatabase::AddLockoutDuration(m_members, lockout, modified_seconds); + ExpeditionDatabase::AddLockoutDuration(GetDynamicZone().GetMembers(), lockout, modified_seconds); ProcessLockoutDuration(lockout, seconds, members_only); SendWorldLockoutDuration(lockout, seconds, members_only); @@ -442,7 +428,7 @@ void Expedition::UpdateLockoutDuration( void Expedition::RemoveLockout(const std::string& event_name) { ExpeditionDatabase::DeleteLockout(m_id, event_name); - ExpeditionDatabase::DeleteMembersLockout(m_members, m_expedition_name, event_name); + ExpeditionDatabase::DeleteMembersLockout(GetDynamicZone().GetMembers(), m_expedition_name, event_name); ExpeditionLockoutTimer lockout{m_uuid, m_expedition_name, event_name, 0, 0}; ProcessLockoutUpdate(lockout, true); @@ -451,12 +437,11 @@ void Expedition::RemoveLockout(const std::string& event_name) bool Expedition::AddMember(const std::string& add_char_name, uint32_t add_char_id) { - if (HasMember(add_char_id)) + if (GetDynamicZone().HasMember(add_char_id)) { return false; } - ExpeditionDatabase::InsertMember(m_id, add_char_id); m_dynamiczone.AddCharacter(add_char_id); ProcessMemberAdded(add_char_name, add_char_id); @@ -469,23 +454,20 @@ void Expedition::RemoveAllMembers(bool enable_removal_timers) { m_dynamiczone.RemoveAllCharacters(enable_removal_timers); - ExpeditionDatabase::DeleteAllMembers(m_id); - SendUpdatesToZoneMembers(true); SendWorldExpeditionUpdate(ServerOP_ExpeditionMembersRemoved); - m_members.clear(); + GetDynamicZone().ClearInternalMembers(); } bool Expedition::RemoveMember(const std::string& remove_char_name) { - auto member = GetMemberData(remove_char_name); + auto member = GetDynamicZone().GetMemberData(remove_char_name); if (!member.IsValid()) { return false; } - ExpeditionDatabase::DeleteMember(m_id, member.id); m_dynamiczone.RemoveCharacter(member.id); ProcessMemberRemoved(member.name, member.id); @@ -501,15 +483,13 @@ void Expedition::SwapMember(Client* add_client, const std::string& remove_char_n return; } - auto member = GetMemberData(remove_char_name); + auto member = GetDynamicZone().GetMemberData(remove_char_name); if (!member.IsValid()) { return; } // make remove and add atomic to avoid racing with separate world messages - ExpeditionDatabase::DeleteMember(m_id, member.id); - ExpeditionDatabase::InsertMember(m_id, add_client->CharacterID()); m_dynamiczone.RemoveCharacter(member.id); m_dynamiczone.AddCharacter(add_client->CharacterID()); @@ -529,19 +509,19 @@ void Expedition::SetMemberStatus(Client* client, DynamicZoneMemberStatus status) void Expedition::SendMemberStatusToZoneMembers(uint32_t update_member_id, DynamicZoneMemberStatus status) { - auto member_data = GetMemberData(update_member_id); + auto member_data = GetDynamicZone().GetMemberData(update_member_id); if (!member_data.IsValid()) { return; } // if zone already had this member status cached avoid packet update to clients - bool changed = SetInternalMemberStatus(update_member_id, status); + bool changed = GetDynamicZone().SetInternalMemberStatus(update_member_id, status); if (changed) { - member_data = GetMemberData(update_member_id); // rules may override status + member_data = GetDynamicZone().GetMemberData(update_member_id); // rules may override status auto outapp_member_status = CreateMemberListStatusPacket(member_data.name, member_data.status); - for (auto& member : m_members) + for (auto& member : GetDynamicZone().GetMembers()) { Client* member_client = entity_list.GetClientByCharID(member.id); if (member_client) @@ -673,7 +653,7 @@ bool Expedition::ProcessAddConflicts(Client* leader_client, Client* add_client, // member swapping integrity is handled by invite response if (!swapping) { - auto member_count = ExpeditionDatabase::GetMemberCount(m_id); + auto member_count = GetDynamicZone().GetDatabaseMemberCount(); if (member_count == 0) { has_conflict = true; @@ -734,8 +714,8 @@ void Expedition::DzInviteResponse(Client* add_client, bool accepted, const std:: // error if swapping and character was already removed before the accept if (was_swap_invite) { - auto swap_member = GetMemberData(swap_remove_name); - if (!swap_member.IsValid() || !ExpeditionDatabase::HasMember(m_id, swap_member.id)) + auto swap_member = GetDynamicZone().GetMemberData(swap_remove_name); + if (!swap_member.IsValid() || !GetDynamicZone().HasDatabaseMember(swap_member.id)) { has_conflicts = true; } @@ -852,7 +832,7 @@ void Expedition::DzAddPlayer( } else { - auto member_data = GetMemberData(add_char_name); + auto member_data = GetDynamicZone().GetMemberData(add_char_name); if (member_data.IsValid()) { // live prioritizes offline message before already a member message @@ -950,7 +930,7 @@ void Expedition::DzSwapPlayer( return; } - if (remove_char_name.empty() || !HasMember(remove_char_name)) + if (remove_char_name.empty() || !GetDynamicZone().HasMember(remove_char_name)) { requester->MessageString(Chat::Red, DZSWAP_CANNOT_REMOVE, FormatName(remove_char_name).c_str()); return; @@ -966,7 +946,7 @@ void Expedition::DzPlayerList(Client* requester) requester->MessageString(Chat::Yellow, EXPEDITION_LEADER, m_leader.name.c_str()); std::string member_names; - for (const auto& member : m_members) + for (const auto& member : GetDynamicZone().GetMembers()) { fmt::format_to(std::back_inserter(member_names), "{}, ", member.name); } @@ -1017,7 +997,7 @@ void Expedition::SetLocked( void Expedition::ProcessLeaderChanged(uint32_t new_leader_id) { - auto new_leader = GetMemberData(new_leader_id); + auto new_leader = GetDynamicZone().GetMemberData(new_leader_id); if (!new_leader.IsValid()) { LogExpeditions("Processed invalid new leader id [{}] for expedition [{}]", new_leader_id, m_id); @@ -1027,11 +1007,11 @@ void Expedition::ProcessLeaderChanged(uint32_t new_leader_id) LogExpeditionsModerate("Replaced [{}] leader [{}] with [{}]", m_id, m_leader.name, new_leader.name); m_leader = new_leader; - m_dynamiczone.SetLeaderName(m_leader.name); + m_dynamiczone.SetLeader(m_leader); // update each client's expedition window in this zone auto outapp_leader = CreateLeaderNamePacket(); - for (const auto& member : m_members) + for (const auto& member : GetDynamicZone().GetMembers()) { Client* member_client = entity_list.GetClientByCharID(member.id); if (member_client) @@ -1074,7 +1054,7 @@ void Expedition::ProcessMakeLeader(Client* old_leader_client, Client* new_leader void Expedition::ProcessMemberAdded(const std::string& char_name, uint32_t added_char_id) { - AddInternalMember({ added_char_id, char_name, DynamicZoneMemberStatus::Online }); + GetDynamicZone().AddInternalMember({ added_char_id, char_name, DynamicZoneMemberStatus::Online }); // adds the member to this expedition and notifies both leader and new member Client* leader_client = entity_list.GetClientByCharID(m_leader.id); @@ -1097,24 +1077,22 @@ void Expedition::ProcessMemberAdded(const std::string& char_name, uint32_t added void Expedition::ProcessMemberRemoved(const std::string& removed_char_name, uint32_t removed_char_id) { - if (m_members.empty()) + if (GetDynamicZone().GetMembers().empty()) { return; } auto outapp_member_name = CreateMemberListNamePacket(removed_char_name, true); - for (auto it = m_members.begin(); it != m_members.end();) + for (const auto& member : GetDynamicZone().GetMembers()) { - bool is_removed = (it->name == removed_char_name); - - Client* member_client = entity_list.GetClientByCharID(it->id); + Client* member_client = entity_list.GetClientByCharID(member.id); if (member_client) { // all members receive the removed player name packet member_client->QueuePacket(outapp_member_name.get()); - if (is_removed) + if (member.id == removed_char_id) { // live doesn't clear expedition info on clients removed while inside dz. // it instead let's the dz kick timer do it even if character zones out @@ -1123,17 +1101,15 @@ void Expedition::ProcessMemberRemoved(const std::string& removed_char_name, uint member_client->SendDzCompassUpdate(); member_client->QueuePacket(CreateInfoPacket(true).get()); member_client->MessageString(Chat::Yellow, EXPEDITION_REMOVED, - it->name.c_str(), m_expedition_name.c_str()); + member.name.c_str(), m_expedition_name.c_str()); } } - - it = is_removed ? m_members.erase(it) : it + 1; } - LogExpeditionsDetail( - "Processed member [{}] ({}) removal from [{}], cache member count: [{}]", - removed_char_name, removed_char_id, m_id, m_members.size() - ); + GetDynamicZone().RemoveInternalMember(removed_char_id); + + LogExpeditionsDetail("Processed member [{}] ({}) removal from [{}], cache member count: [{}]", + removed_char_name, removed_char_id, m_id, GetDynamicZone().GetMemberCount()); } void Expedition::ProcessLockoutDuration( @@ -1152,7 +1128,7 @@ void Expedition::ProcessLockoutDuration( } } - for (const auto& member : m_members) + for (const auto& member : GetDynamicZone().GetMembers()) { Client* member_client = entity_list.GetClientByCharID(member.id); if (member_client) @@ -1205,7 +1181,7 @@ void Expedition::ProcessLockoutUpdate( } } - for (const auto& member : m_members) + for (const auto& member : GetDynamicZone().GetMembers()) { Client* member_client = entity_list.GetClientByCharID(member.id); if (member_client) @@ -1254,7 +1230,7 @@ void Expedition::SendMemberListToZoneMembers() { auto outapp_members = CreateMemberListPacket(false); - for (const auto& member : m_members) + for (const auto& member : GetDynamicZone().GetMembers()) { Client* member_client = entity_list.GetClientByCharID(member.id); if (member_client) @@ -1266,12 +1242,12 @@ void Expedition::SendMemberListToZoneMembers() void Expedition::SendUpdatesToZoneMembers(bool clear, bool message_on_clear) { - if (!m_members.empty()) + if (GetDynamicZone().HasMembers()) { auto outapp_info = CreateInfoPacket(clear); auto outapp_members = CreateMemberListPacket(clear); - for (const auto& member : m_members) + for (const auto& member : GetDynamicZone().GetMembers()) { Client* member_client = entity_list.GetClientByCharID(member.id); if (member_client) @@ -1351,7 +1327,7 @@ std::unique_ptr Expedition::CreateInvitePacket( std::unique_ptr Expedition::CreateMemberListPacket(bool clear) { - uint32_t member_count = clear ? 0 : static_cast(m_members.size()); + uint32_t member_count = clear ? 0 : static_cast(GetDynamicZone().GetMemberCount()); uint32_t member_entries_size = sizeof(DynamicZoneMemberEntry_Struct) * member_count; uint32_t outsize = sizeof(DynamicZoneMemberList_Struct) + member_entries_size; auto outapp = std::make_unique(OP_DzMemberList, outsize); @@ -1361,10 +1337,11 @@ std::unique_ptr Expedition::CreateMemberListPacket(bool cle if (!clear) { - for (auto i = 0; i < m_members.size(); ++i) + const auto& members = GetDynamicZone().GetMembers(); + for (auto i = 0; i < members.size(); ++i) { - strn0cpy(buf->members[i].name, m_members[i].name.c_str(), sizeof(buf->members[i].name)); - buf->members[i].online_status = static_cast(m_members[i].status); + strn0cpy(buf->members[i].name, members[i].name.c_str(), sizeof(buf->members[i].name)); + buf->members[i].online_status = static_cast(members[i].status); } } @@ -1662,7 +1639,7 @@ void Expedition::HandleWorldMessage(ServerPacket* pack) if (expedition) { expedition->SendUpdatesToZoneMembers(true); - expedition->m_members.clear(); + expedition->GetDynamicZone().ClearInternalMembers(); } } break; @@ -1785,7 +1762,7 @@ void Expedition::HandleWorldMessage(ServerPacket* pack) for (uint32_t i = 0; i < buf->count; ++i) { auto status = static_cast(buf->entries[i].online_status); - expedition->SetInternalMemberStatus(buf->entries[i].character_id, status); + expedition->GetDynamicZone().SetInternalMemberStatus(buf->entries[i].character_id, status); } expedition->SendMemberListToZoneMembers(); } @@ -1865,7 +1842,7 @@ void Expedition::HandleWorldMessage(ServerPacket* pack) void Expedition::SendCompassUpdateToZoneMembers() { - for (const auto& member : m_members) + for (const auto& member : GetDynamicZone().GetMembers()) { Client* member_client = entity_list.GetClientByCharID(member.id); if (member_client) @@ -1979,7 +1956,7 @@ void Expedition::SendMembersExpireWarning(uint32_t minutes_remaining) { // expeditions warn members in all zones not just the dz auto outapp = CreateExpireWarningPacket(minutes_remaining); - for (const auto& member : m_members) + for (const auto& member : GetDynamicZone().GetMembers()) { Client* member_client = entity_list.GetClientByCharID(member.id); if (member_client) diff --git a/zone/expedition.h b/zone/expedition.h index b3404d6965..56ffffc3c6 100644 --- a/zone/expedition.h +++ b/zone/expedition.h @@ -142,7 +142,6 @@ class Expedition : public ExpeditionBase void ProcessMemberAdded(const std::string& added_char_name, uint32_t added_char_id); void ProcessMemberRemoved(const std::string& removed_char_name, uint32_t removed_char_id); void SaveLockouts(ExpeditionRequest& request); - void SaveMembers(ExpeditionRequest& request); void SendClientExpeditionInvite( Client* client, const std::string& inviter_name, const std::string& swap_remove_name); void SendLeaderMessage(Client* leader_client, uint16_t chat_type, uint32_t string_id, diff --git a/zone/expedition_database.cpp b/zone/expedition_database.cpp index af6948f5ff..eb31c301cc 100644 --- a/zone/expedition_database.cpp +++ b/zone/expedition_database.cpp @@ -213,67 +213,6 @@ void ExpeditionDatabase::DeleteLockout(uint32_t expedition_id, const std::string database.QueryDatabase(query); } -uint32_t ExpeditionDatabase::GetExpeditionIDFromCharacterID(uint32_t character_id) -{ - LogExpeditionsDetail("Getting expedition id for character [{}]", character_id); - - uint32_t expedition_id = 0; - auto query = fmt::format(SQL( - SELECT expedition_id FROM expedition_members - WHERE character_id = {} AND is_current_member = TRUE; - ), character_id); - - auto results = database.QueryDatabase(query); - if (results.Success() && results.RowCount() > 0) - { - auto row = results.begin(); - expedition_id = strtoul(row[0], nullptr, 10); - } - return expedition_id; -} - -uint32_t ExpeditionDatabase::GetMemberCount(uint32_t expedition_id) -{ - LogExpeditionsDetail("Getting expedition [{}] member count from db", expedition_id); - - uint32_t member_count = 0; - if (expedition_id != 0) - { - auto query = fmt::format(SQL( - SELECT COUNT(*) - FROM expedition_members - WHERE expedition_id = {} AND is_current_member = TRUE; - ), expedition_id); - - auto results = database.QueryDatabase(query); - if (results.Success() && results.RowCount() > 0) - { - auto row = results.begin(); - member_count = strtoul(row[0], nullptr, 10); - } - } - return member_count; -} - -bool ExpeditionDatabase::HasMember(uint32_t expedition_id, uint32_t character_id) -{ - LogExpeditionsDetail("Checking db expedition [{}] for character [{}]", expedition_id, character_id); - - if (expedition_id == 0 || character_id == 0) - { - return false; - } - - auto query = fmt::format(SQL( - SELECT id - FROM expedition_members - WHERE expedition_id = {} AND character_id = {} AND is_current_member = TRUE; - ), expedition_id, character_id); - - auto results = database.QueryDatabase(query); - return (results.Success() && results.RowCount() > 0); -} - void ExpeditionDatabase::InsertCharacterLockouts(uint32_t character_id, const std::vector& lockouts) { @@ -415,50 +354,6 @@ void ExpeditionDatabase::InsertLockouts( } } -void ExpeditionDatabase::InsertMember(uint32_t expedition_id, uint32_t character_id) -{ - LogExpeditionsDetail("Inserting character [{}] into expedition [{}]", character_id, expedition_id); - - auto query = fmt::format(SQL( - INSERT INTO expedition_members - (expedition_id, character_id) - VALUES - ({}, {}) - ON DUPLICATE KEY UPDATE is_current_member = TRUE; - ), expedition_id, character_id); - - database.QueryDatabase(query); -} - -void ExpeditionDatabase::InsertMembers( - uint32_t expedition_id, const std::vector& members) -{ - LogExpeditionsDetail("Inserting characters into expedition [{}]", expedition_id); - - std::string insert_values; - for (const auto& member : members) - { - fmt::format_to(std::back_inserter(insert_values), - "({}, {}),", - expedition_id, member.id - ); - } - - if (!insert_values.empty()) - { - insert_values.pop_back(); // trailing comma - - auto query = fmt::format(SQL( - INSERT INTO expedition_members - (expedition_id, character_id) - VALUES {} - ON DUPLICATE KEY UPDATE is_current_member = TRUE; - ), insert_values); - - database.QueryDatabase(query); - } -} - void ExpeditionDatabase::UpdateLockState(uint32_t expedition_id, bool is_locked) { LogExpeditionsDetail("Updating lock state [{}] for expedition [{}]", is_locked, expedition_id); @@ -470,29 +365,6 @@ void ExpeditionDatabase::UpdateLockState(uint32_t expedition_id, bool is_locked) database.QueryDatabase(query); } -void ExpeditionDatabase::DeleteMember(uint32_t expedition_id, uint32_t character_id) -{ - LogExpeditionsDetail("Removing member [{}] from expedition [{}]", character_id, expedition_id); - - auto query = fmt::format(SQL( - UPDATE expedition_members SET is_current_member = FALSE - WHERE expedition_id = {} AND character_id = {}; - ), expedition_id, character_id); - - database.QueryDatabase(query); -} - -void ExpeditionDatabase::DeleteAllMembers(uint32_t expedition_id) -{ - LogExpeditionsDetail("Removing all members of expedition [{}]", expedition_id); - - auto query = fmt::format(SQL( - UPDATE expedition_members SET is_current_member = FALSE WHERE expedition_id = {}; - ), expedition_id); - - database.QueryDatabase(query); -} - void ExpeditionDatabase::UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join) { LogExpeditionsDetail("Updating replay lockout on join [{}] for expedition [{}]", add_on_join, expedition_id); diff --git a/zone/expedition_database.h b/zone/expedition_database.h index cce81c0fca..e833329205 100644 --- a/zone/expedition_database.h +++ b/zone/expedition_database.h @@ -41,8 +41,6 @@ namespace ExpeditionDatabase std::vector LoadCharacterLockouts(uint32_t character_id); std::vector LoadCharacterLockouts(uint32_t character_id, const std::string& expedition_name); - void DeleteAllMembers(uint32_t expedition_id); - void DeleteMember(uint32_t expedition_id, uint32_t character_id); void DeleteAllCharacterLockouts(uint32_t character_id); void DeleteAllCharacterLockouts(uint32_t character_id, const std::string& expedition_name); void DeleteCharacterLockout(uint32_t character_id, const std::string& expedition_name, @@ -50,9 +48,6 @@ namespace ExpeditionDatabase void DeleteLockout(uint32_t expedition_id, const std::string& event_name); void DeleteMembersLockout(const std::vector& members, const std::string& expedition_name, const std::string& event_name); - uint32_t GetExpeditionIDFromCharacterID(uint32_t character_id); - uint32_t GetMemberCount(uint32_t expedition_id); - bool HasMember(uint32_t expedition_id, uint32_t character_id); void InsertCharacterLockouts(uint32_t character_id, const std::vector& lockouts); void InsertMembersLockout(const std::vector& members, @@ -60,8 +55,6 @@ namespace ExpeditionDatabase void InsertLockout(uint32_t expedition_id, const ExpeditionLockoutTimer& lockout); void InsertLockouts(uint32_t expedition_id, const std::unordered_map& lockouts); - void InsertMember(uint32_t expedition_id, uint32_t character_id); - void InsertMembers(uint32_t expedition_id, const std::vector& members); void UpdateLockState(uint32_t expedition_id, bool is_locked); void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join); void AddLockoutDuration(const std::vector& members, diff --git a/zone/expedition_request.h b/zone/expedition_request.h index 64c594d3cb..b5e69e3efe 100644 --- a/zone/expedition_request.h +++ b/zone/expedition_request.h @@ -47,8 +47,8 @@ class ExpeditionRequest const std::string& GetNotAllAddedMessage() const { return m_not_all_added_msg; } uint32_t GetMinPlayers() const { return m_min_players; } uint32_t GetMaxPlayers() const { return m_max_players; } - std::vector GetMembers() const { return m_members; } - std::unordered_map GetLockouts() const { return m_lockouts; } + const std::vector& GetMembers() const { return m_members; } + const std::unordered_map& GetLockouts() const { return m_lockouts; } private: bool CanMembersJoin(const std::vector& member_names); diff --git a/zone/lua_expedition.cpp b/zone/lua_expedition.cpp index f19e417ff7..b3a442a242 100644 --- a/zone/lua_expedition.cpp +++ b/zone/lua_expedition.cpp @@ -104,7 +104,7 @@ std::string Lua_Expedition::GetLootEventBySpawnID(uint32_t spawn_id) { uint32_t Lua_Expedition::GetMemberCount() { Lua_Safe_Call_Int(); - return self->GetMemberCount(); + return self->GetDynamicZone().GetMemberCount(); } luabind::object Lua_Expedition::GetMembers(lua_State* L) { @@ -113,7 +113,7 @@ luabind::object Lua_Expedition::GetMembers(lua_State* L) { if (d_) { auto self = reinterpret_cast(d_); - for (const auto& member : self->GetMembers()) + for (const auto& member : self->GetDynamicZone().GetMembers()) { lua_table[member.name] = member.id; } diff --git a/zone/perl_expedition.cpp b/zone/perl_expedition.cpp index c0c483cfbb..3715e754a5 100644 --- a/zone/perl_expedition.cpp +++ b/zone/perl_expedition.cpp @@ -247,7 +247,7 @@ XS(XS_Expedition_GetMemberCount) { Expedition* THIS = nullptr; VALIDATE_THIS_IS_EXPEDITION; - XSRETURN_UV(THIS->GetMemberCount()); + XSRETURN_UV(THIS->GetDynamicZone().GetMemberCount()); } XS(XS_Expedition_GetMembers); @@ -262,8 +262,7 @@ XS(XS_Expedition_GetMembers) { HV* hash = newHV(); - auto members = THIS->GetMembers(); - for (const auto& member : members) + for (const auto& member : THIS->GetDynamicZone().GetMembers()) { hv_store(hash, member.name.c_str(), static_cast(member.name.size()), newSVuv(member.id), 0);