diff --git a/zone/expedition_database.cpp b/zone/expedition_database.cpp index 1c4bf6207..27b634acf 100644 --- a/zone/expedition_database.cpp +++ b/zone/expedition_database.cpp @@ -186,34 +186,49 @@ ExpeditionDatabase::LoadMultipleExpeditionLockouts( return lockouts; } -MySQLRequestResult ExpeditionDatabase::LoadValidationData( - const std::string& character_names, const std::string& expedition_name) +MySQLRequestResult ExpeditionDatabase::LoadMembersForCreateRequest( + const std::vector& character_names, const std::string& expedition_name) { LogExpeditionsDetail("Loading multiple characters data for [{}] request validation", expedition_name); - // for create validation, loads each character's lockouts and possible current expedition - auto query = fmt::format(SQL( - SELECT - character_data.id, - character_data.name, - member.expedition_id, - UNIX_TIMESTAMP(lockout.expire_time), - lockout.duration, - lockout.event_name - FROM character_data - LEFT JOIN expedition_character_lockouts lockout - ON character_data.id = lockout.character_id - AND lockout.is_pending = FALSE - AND lockout.expire_time > NOW() - AND lockout.expedition_name = '{}' - LEFT JOIN expedition_members member - ON character_data.id = member.character_id - AND member.is_current_member = TRUE - WHERE character_data.name IN ({}) - ORDER BY character_data.id; - ), expedition_name, character_names); + std::string in_character_names_query; + for (const auto& character_name : character_names) + { + fmt::format_to(std::back_inserter(in_character_names_query), "'{}',", character_name); + } - return database.QueryDatabase(query); + MySQLRequestResult results; + + if (!in_character_names_query.empty()) + { + in_character_names_query.pop_back(); // trailing comma + + // for create validation, loads each character's lockouts and possible current expedition + auto query = fmt::format(SQL( + SELECT + character_data.id, + character_data.name, + member.expedition_id, + UNIX_TIMESTAMP(lockout.expire_time), + lockout.duration, + lockout.event_name + FROM character_data + LEFT JOIN expedition_character_lockouts lockout + ON character_data.id = lockout.character_id + AND lockout.is_pending = FALSE + AND lockout.expire_time > NOW() + AND lockout.expedition_name = '{}' + LEFT JOIN expedition_members member + ON character_data.id = member.character_id + AND member.is_current_member = TRUE + WHERE character_data.name IN ({}) + ORDER BY character_data.id; + ), expedition_name, in_character_names_query); + + results = database.QueryDatabase(query); + } + + return results; } void ExpeditionDatabase::DeleteAllCharacterLockouts(uint32_t character_id) diff --git a/zone/expedition_database.h b/zone/expedition_database.h index e6e35368e..ba9f99c3d 100644 --- a/zone/expedition_database.h +++ b/zone/expedition_database.h @@ -43,7 +43,8 @@ namespace ExpeditionDatabase MySQLRequestResult LoadAllExpeditions(); MySQLRequestResult LoadCharacterLockouts(uint32_t character_id); MySQLRequestResult LoadCharacterLockouts(uint32_t character_id, const std::string& expedition_name); - MySQLRequestResult LoadValidationData(const std::string& character_names_query, const std::string& expedition_name); + MySQLRequestResult LoadMembersForCreateRequest( + const std::vector& character_names, const std::string& expedition_name); std::unordered_map> LoadMultipleExpeditionLockouts(const std::vector& expedition_ids); void DeleteAllCharacterLockouts(uint32_t character_id); diff --git a/zone/expedition_request.cpp b/zone/expedition_request.cpp index 0474c18e6..8cc0eead0 100644 --- a/zone/expedition_request.cpp +++ b/zone/expedition_request.cpp @@ -78,7 +78,7 @@ bool ExpeditionRequest::Validate(Client* requester) m_leader = m_requester; m_leader_id = m_requester->CharacterID(); m_leader_name = m_requester->GetName(); - requirements_met = ValidateMembers(fmt::format("'{}'", m_leader_name), 1); + requirements_met = ValidateMembers({m_leader_name}); } auto elapsed = benchmark.elapsed(); @@ -93,23 +93,16 @@ bool ExpeditionRequest::CanRaidRequest(Raid* raid) m_leader_name = raid->leadername; m_leader_id = m_leader ? m_leader->CharacterID() : database.GetCharacterID(raid->leadername); - uint32_t count = 0; - std::string query_member_names; + std::vector member_names; for (int i = 0; i < MAX_RAID_MEMBERS; ++i) { if (raid->members[i].membername[0]) { - fmt::format_to(std::back_inserter(query_member_names), "'{}',", raid->members[i].membername); - ++count; + member_names.emplace_back(raid->members[i].membername); } } - if (!query_member_names.empty()) - { - query_member_names.pop_back(); // trailing comma - } - - return ValidateMembers(query_member_names, count); + return ValidateMembers(member_names); } bool ExpeditionRequest::CanGroupRequest(Group* group) @@ -124,22 +117,16 @@ bool ExpeditionRequest::CanGroupRequest(Group* group) m_leader_id = m_leader ? m_leader->CharacterID() : database.GetCharacterID(m_leader_name.c_str()); uint32_t count = 0; - std::string query_member_names; + std::vector member_names; for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) { if (group->membername[i][0]) { - fmt::format_to(std::back_inserter(query_member_names), "'{}',", group->membername[i]); - ++count; + member_names.emplace_back(group->membername[i]); } } - if (!query_member_names.empty()) - { - query_member_names.pop_back(); // trailing comma - } - - return ValidateMembers(query_member_names, count); + return ValidateMembers(member_names); } std::string ExpeditionRequest::GetGroupLeaderName(uint32_t group_id) @@ -149,27 +136,16 @@ std::string ExpeditionRequest::GetGroupLeaderName(uint32_t group_id) return std::string(leader_name_buffer); } -bool ExpeditionRequest::ValidateMembers(const std::string& query_member_names, uint32_t member_count) +bool ExpeditionRequest::ValidateMembers(const std::vector& member_names) { - if (query_member_names.empty() || !LoadLeaderLockouts()) + if (member_names.empty()) { return false; } - // get character ids for all members through database since some may be out - // of zone. also gets each member's existing expeditions and/or lockouts - auto results = ExpeditionDatabase::LoadValidationData(query_member_names, m_expedition_name); - if (!results.Success()) - { - LogExpeditions("Failed to load data to verify members for expedition request"); - return false; - } - bool requirements_met = true; - bool is_solo = (member_count == 1); - bool has_conflicts = CheckMembersForConflicts(results, is_solo); - if (has_conflicts) + if (CheckMembersForConflicts(member_names)) { requirements_met = false; } @@ -178,7 +154,7 @@ bool ExpeditionRequest::ValidateMembers(const std::string& query_member_names, u // maybe it's done intentionally as a way to preview lockout conflicts if (requirements_met) { - requirements_met = IsPlayerCountValidated(member_count); + requirements_met = IsPlayerCountValidated(static_cast(member_names.size())); } return requirements_met; @@ -225,21 +201,29 @@ bool ExpeditionRequest::LoadLeaderLockouts() return true; } -bool ExpeditionRequest::CheckMembersForConflicts(MySQLRequestResult& results, bool is_solo) +bool ExpeditionRequest::CheckMembersForConflicts(const std::vector& member_names) { - // leader lockouts were pre-loaded to compare with members below + // load data for each member and compare with leader lockouts + auto results = ExpeditionDatabase::LoadMembersForCreateRequest(member_names, m_expedition_name); + if (!results.Success() || !LoadLeaderLockouts()) + { + LogExpeditions("Failed to load data to verify members for expedition request"); + return true; + } + + bool is_solo = (member_names.size() == 1); bool has_conflicts = false; std::vector member_lockout_conflicts; auto leeway_seconds = static_cast(RuleI(Expedition, RequestExpiredLockoutLeewaySeconds)); - bool leader_processed = false; uint32_t last_character_id = 0; for (auto row = results.begin(); row != results.end(); ++row) { auto character_id = static_cast(std::strtoul(row[0], nullptr, 10)); std::string character_name(row[1]); + bool has_expedition = (row[2] != nullptr); // in expedition_members with another expedition if (character_id != last_character_id) { @@ -253,8 +237,7 @@ bool ExpeditionRequest::CheckMembersForConflicts(MySQLRequestResult& results, bo } member_lockout_conflicts.clear(); - // current character existing expedition check - if (row[2]) + if (has_expedition) { has_conflicts = true; SendLeaderMemberInExpedition(character_name, is_solo); @@ -293,15 +276,13 @@ bool ExpeditionRequest::CheckMembersForConflicts(MySQLRequestResult& results, bo { has_conflicts = true; SendLeaderMemberReplayLockout(character_name, lockout, is_solo); - // replay timers no longer also show up as event conflicts - //SendLeaderMemberEventLockout(character_name, lockout); } else if (m_check_event_lockouts && character_id != m_leader_id) { if (m_lockouts.find(event_name) == m_lockouts.end()) { - // leader doesn't have this lockout - // queue instead of messaging now so they come after any replay lockout messages + // leader doesn't have this lockout. queue instead of messaging + // now so message comes after any replay lockout messages has_conflicts = true; member_lockout_conflicts.emplace_back(ExpeditionRequestConflict{character_name, lockout}); } @@ -348,7 +329,7 @@ void ExpeditionRequest::SendLeaderMemberInExpedition(const std::string& member_n void ExpeditionRequest::SendLeaderMemberReplayLockout( const std::string& member_name, const ExpeditionLockoutTimer& lockout, bool is_solo) { - if (m_disable_messages || lockout.GetSecondsRemaining() <= 0) + if (m_disable_messages) { return; } @@ -371,7 +352,7 @@ void ExpeditionRequest::SendLeaderMemberReplayLockout( void ExpeditionRequest::SendLeaderMemberEventLockout( const std::string& member_name, const ExpeditionLockoutTimer& lockout) { - if (m_disable_messages || lockout.GetSecondsRemaining() <= 0) + if (m_disable_messages) { return; } diff --git a/zone/expedition_request.h b/zone/expedition_request.h index 569dcc6ae..f128cc4c4 100644 --- a/zone/expedition_request.h +++ b/zone/expedition_request.h @@ -54,10 +54,10 @@ public: std::unordered_map TakeLockouts() && { return std::move(m_lockouts); } private: - bool ValidateMembers(const std::string& query_member_names, uint32_t member_count); + bool ValidateMembers(const std::vector& member_names); bool CanRaidRequest(Raid* raid); bool CanGroupRequest(Group* group); - bool CheckMembersForConflicts(MySQLRequestResult& results, bool is_solo); + bool CheckMembersForConflicts(const std::vector& member_names); std::string GetGroupLeaderName(uint32_t group_id); bool IsPlayerCountValidated(uint32_t member_count); bool LoadLeaderLockouts();