Remove member history from expeditions

Expedition uuids are now used to check if characters may re-join
This commit is contained in:
hg 2020-06-13 20:19:03 -04:00
parent da2a6205ed
commit 06d84b83de
8 changed files with 40 additions and 63 deletions

View File

@ -35,7 +35,6 @@ CREATE TABLE `expedition_members` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`expedition_id` INT(10) UNSIGNED NOT NULL DEFAULT 0, `expedition_id` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`character_id` INT(10) UNSIGNED NOT NULL DEFAULT 0, `character_id` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`is_current_member` TINYINT(4) UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE INDEX `expedition_id_character_id` (`expedition_id`, `character_id`), UNIQUE INDEX `expedition_id_character_id` (`expedition_id`, `character_id`),
CONSTRAINT `FK_expedition_members_expedition_details` FOREIGN KEY (`expedition_id`) REFERENCES `expedition_details` (`id`) ON DELETE CASCADE CONSTRAINT `FK_expedition_members_expedition_details` FOREIGN KEY (`expedition_id`) REFERENCES `expedition_details` (`id`) ON DELETE CASCADE

View File

@ -205,20 +205,19 @@ void ExpeditionCache::Process()
void ExpeditionDatabase::PurgeExpiredExpeditions() void ExpeditionDatabase::PurgeExpiredExpeditions()
{ {
LogExpeditionsDetail("Purging expired expeditions");
std::string query = SQL( std::string query = SQL(
DELETE expedition FROM expedition_details expedition DELETE expedition
FROM expedition_details expedition
LEFT JOIN instance_list ON expedition.instance_id = instance_list.id LEFT JOIN instance_list ON expedition.instance_id = instance_list.id
LEFT JOIN ( LEFT JOIN (
SELECT expedition_id, COUNT(IF(is_current_member = TRUE, 1, NULL)) member_count SELECT expedition_id, COUNT(*) member_count
FROM expedition_members FROM expedition_members
GROUP BY expedition_id GROUP BY expedition_id
) AS expedition_members ) AS expedition_members
ON expedition_members.expedition_id = expedition.id ON expedition_members.expedition_id = expedition.id
WHERE WHERE
expedition.instance_id IS NULL expedition.instance_id IS NULL
OR expedition_members.member_count = 0 OR expedition_members.member_count IS NULL
OR (instance_list.start_time + instance_list.duration) <= UNIX_TIMESTAMP(); OR (instance_list.start_time + instance_list.duration) <= UNIX_TIMESTAMP();
); );
@ -227,8 +226,6 @@ void ExpeditionDatabase::PurgeExpiredExpeditions()
void ExpeditionDatabase::PurgeExpiredCharacterLockouts() void ExpeditionDatabase::PurgeExpiredCharacterLockouts()
{ {
LogExpeditionsDetail("Purging expired lockouts");
std::string query = SQL( std::string query = SQL(
DELETE FROM expedition_character_lockouts DELETE FROM expedition_character_lockouts
WHERE expire_time <= NOW(); WHERE expire_time <= NOW();
@ -239,8 +236,6 @@ void ExpeditionDatabase::PurgeExpiredCharacterLockouts()
std::vector<Expedition> ExpeditionDatabase::LoadExpeditions() std::vector<Expedition> ExpeditionDatabase::LoadExpeditions()
{ {
LogExpeditionsDetail("Loading expeditions for world cache");
std::vector<Expedition> expeditions; std::vector<Expedition> expeditions;
std::string query = SQL( std::string query = SQL(
@ -253,9 +248,7 @@ std::vector<Expedition> ExpeditionDatabase::LoadExpeditions()
expedition_members.character_id expedition_members.character_id
FROM expedition_details FROM expedition_details
INNER JOIN instance_list ON expedition_details.instance_id = instance_list.id INNER JOIN instance_list ON expedition_details.instance_id = instance_list.id
INNER JOIN expedition_members INNER JOIN expedition_members ON expedition_members.expedition_id = expedition_details.id
ON expedition_members.expedition_id = expedition_details.id
AND expedition_members.is_current_member = TRUE
ORDER BY expedition_details.id; ORDER BY expedition_details.id;
); );
@ -305,9 +298,7 @@ Expedition ExpeditionDatabase::LoadExpedition(uint32_t expedition_id)
expedition_members.character_id expedition_members.character_id
FROM expedition_details FROM expedition_details
INNER JOIN instance_list ON expedition_details.instance_id = instance_list.id INNER JOIN instance_list ON expedition_details.instance_id = instance_list.id
INNER JOIN expedition_members INNER JOIN expedition_members ON expedition_members.expedition_id = expedition_details.id
ON expedition_members.expedition_id = expedition_details.id
AND expedition_members.is_current_member = TRUE
WHERE expedition_details.id = {}; WHERE expedition_details.id = {};
), expedition_id); ), expedition_id);

View File

@ -427,7 +427,7 @@ void DynamicZone::RemoveAllCharacters(bool enable_removal_timers)
database.RemoveClientsFromInstance(GetInstanceID()); database.RemoveClientsFromInstance(GetInstanceID());
} }
void DynamicZone::SaveInstanceMembersToDatabase(const std::unordered_set<uint32_t>& character_ids) void DynamicZone::SaveInstanceMembersToDatabase(const std::vector<uint32_t>& character_ids)
{ {
LogDynamicZonesDetail("Saving [{}] instance members to database", character_ids.size()); LogDynamicZonesDetail("Saving [{}] instance members to database", character_ids.size());

View File

@ -25,7 +25,6 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <vector> #include <vector>
class MySQLRequestRow; class MySQLRequestRow;
@ -75,7 +74,7 @@ public:
uint32_t CreateInstance(); uint32_t CreateInstance();
void AddCharacter(uint32_t character_id); void AddCharacter(uint32_t character_id);
void SaveInstanceMembersToDatabase(const std::unordered_set<uint32_t>& character_ids); void SaveInstanceMembersToDatabase(const std::vector<uint32_t>& character_ids);
uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); } uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); }
uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_instance_id); }; uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_instance_id); };

View File

@ -212,9 +212,8 @@ void Expedition::CacheExpeditions(MySQLRequestResult& results)
if (current_expedition) if (current_expedition)
{ {
auto member_id = strtoul(row[col::member_id], nullptr, 10); auto member_id = strtoul(row[col::member_id], nullptr, 10);
bool is_current_member = (strtoul(row[col::is_current_member], nullptr, 10) != 0);
current_expedition->AddInternalMember( current_expedition->AddInternalMember(
row[col::member_name], member_id, ExpeditionMemberStatus::Offline, is_current_member row[col::member_name], member_id, ExpeditionMemberStatus::Offline
); );
expedition_character_ids.emplace_back(std::make_pair(expedition_id, member_id)); expedition_character_ids.emplace_back(std::make_pair(expedition_id, member_id));
} }
@ -309,14 +308,16 @@ void Expedition::SaveLockouts(ExpeditionRequest& request)
void Expedition::SaveMembers(ExpeditionRequest& request) void Expedition::SaveMembers(ExpeditionRequest& request)
{ {
m_members = request.GetMembers(); m_members = request.GetMembers();
std::vector<uint32_t> member_ids;
for (const auto& member : m_members) for (const auto& member : m_members)
{ {
m_member_id_history.emplace(member.char_id); member_ids.emplace_back(member.char_id);
} }
ExpeditionDatabase::InsertMembers(m_id, m_members); ExpeditionDatabase::InsertMembers(m_id, m_members);
ExpeditionDatabase::DeleteAllMembersPendingLockouts(m_members); ExpeditionDatabase::DeleteAllMembersPendingLockouts(m_members);
m_dynamiczone.SaveInstanceMembersToDatabase(m_member_id_history); // all are current members here m_dynamiczone.SaveInstanceMembersToDatabase(member_ids);
} }
Expedition* Expedition::FindCachedExpeditionByCharacterID(uint32_t character_id) Expedition* Expedition::FindCachedExpeditionByCharacterID(uint32_t character_id)
@ -465,22 +466,17 @@ void Expedition::RemoveLockout(const std::string& event_name)
} }
void Expedition::AddInternalMember( void Expedition::AddInternalMember(
const std::string& char_name, uint32_t character_id, ExpeditionMemberStatus status, bool is_current_member) const std::string& char_name, uint32_t character_id, ExpeditionMemberStatus status)
{ {
if (is_current_member) auto it = std::find_if(m_members.begin(), m_members.end(),
[character_id](const ExpeditionMember& member) {
return member.char_id == character_id;
});
if (it == m_members.end())
{ {
auto it = std::find_if(m_members.begin(), m_members.end(), m_members.emplace_back(ExpeditionMember{character_id, char_name, status});
[character_id](const ExpeditionMember& member) {
return member.char_id == character_id;
});
if (it == m_members.end())
{
m_members.emplace_back(ExpeditionMember{character_id, char_name, status});
}
} }
m_member_id_history.emplace(character_id);
} }
bool Expedition::AddMember(const std::string& add_char_name, uint32_t add_char_id) bool Expedition::AddMember(const std::string& add_char_name, uint32_t add_char_id)
@ -504,7 +500,7 @@ void Expedition::RemoveAllMembers(bool enable_removal_timers)
m_dynamiczone.RemoveAllCharacters(enable_removal_timers); m_dynamiczone.RemoveAllCharacters(enable_removal_timers);
ExpeditionDatabase::DeleteAllMembersPendingLockouts(m_members); ExpeditionDatabase::DeleteAllMembersPendingLockouts(m_members);
ExpeditionDatabase::UpdateAllMembersRemoved(m_id); ExpeditionDatabase::DeleteAllMembers(m_id);
SendUpdatesToZoneMembers(true); SendUpdatesToZoneMembers(true);
SendWorldExpeditionUpdate(ServerOP_ExpeditionMembersRemoved); SendWorldExpeditionUpdate(ServerOP_ExpeditionMembersRemoved);
@ -520,7 +516,7 @@ bool Expedition::RemoveMember(const std::string& remove_char_name)
return false; return false;
} }
ExpeditionDatabase::UpdateMemberRemoved(m_id, member.char_id); ExpeditionDatabase::DeleteMember(m_id, member.char_id);
m_dynamiczone.RemoveCharacter(member.char_id); m_dynamiczone.RemoveCharacter(member.char_id);
ProcessMemberRemoved(member.name, member.char_id); ProcessMemberRemoved(member.name, member.char_id);
@ -549,7 +545,7 @@ void Expedition::SwapMember(Client* add_client, const std::string& remove_char_n
} }
// make remove and add atomic to avoid racing with separate world messages // make remove and add atomic to avoid racing with separate world messages
ExpeditionDatabase::UpdateMemberRemoved(m_id, member.char_id); ExpeditionDatabase::DeleteMember(m_id, member.char_id);
ExpeditionDatabase::InsertMember(m_id, add_client->CharacterID()); ExpeditionDatabase::InsertMember(m_id, add_client->CharacterID());
m_dynamiczone.RemoveCharacter(member.char_id); m_dynamiczone.RemoveCharacter(member.char_id);
m_dynamiczone.AddCharacter(add_client->CharacterID()); m_dynamiczone.AddCharacter(add_client->CharacterID());

View File

@ -27,7 +27,6 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <vector> #include <vector>
class Client; class Client;
@ -138,7 +137,7 @@ private:
static void CacheExpeditions(MySQLRequestResult& results); static void CacheExpeditions(MySQLRequestResult& results);
static void SendWorldGetOnlineMembers(const std::vector<std::pair<uint32_t, uint32_t>>& expedition_character_ids); static void SendWorldGetOnlineMembers(const std::vector<std::pair<uint32_t, uint32_t>>& expedition_character_ids);
void AddInternalMember(const std::string& char_name, uint32_t char_id, ExpeditionMemberStatus status, bool is_current_member = true); void AddInternalMember(const std::string& char_name, uint32_t char_id, ExpeditionMemberStatus status);
bool ChooseNewLeader(); bool ChooseNewLeader();
bool ConfirmLeaderCommand(Client* requester); bool ConfirmLeaderCommand(Client* requester);
bool ProcessAddConflicts(Client* leader_client, Client* add_client, bool swapping); bool ProcessAddConflicts(Client* leader_client, Client* add_client, bool swapping);
@ -183,8 +182,7 @@ private:
std::string m_expedition_name; std::string m_expedition_name;
DynamicZone m_dynamiczone { DynamicZoneType::Expedition }; DynamicZone m_dynamiczone { DynamicZoneType::Expedition };
ExpeditionMember m_leader; ExpeditionMember m_leader;
std::vector<ExpeditionMember> m_members; // current members std::vector<ExpeditionMember> m_members;
std::unordered_set<uint32_t> m_member_id_history; // track past members to allow invites for replay timer bypass
std::unordered_map<std::string, ExpeditionLockoutTimer> m_lockouts; std::unordered_map<std::string, ExpeditionLockoutTimer> m_lockouts;
}; };

View File

@ -65,7 +65,6 @@ std::string ExpeditionDatabase::LoadExpeditionsSelectQuery()
expedition_details.is_locked, expedition_details.is_locked,
character_data.name leader_name, character_data.name leader_name,
expedition_members.character_id, expedition_members.character_id,
expedition_members.is_current_member,
member_data.name member_data.name
FROM expedition_details FROM expedition_details
INNER JOIN character_data ON expedition_details.leader_id = character_data.id INNER JOIN character_data ON expedition_details.leader_id = character_data.id
@ -259,9 +258,7 @@ MySQLRequestResult ExpeditionDatabase::LoadMembersForCreateRequest(
AND lockout.is_pending = FALSE AND lockout.is_pending = FALSE
AND lockout.expire_time > NOW() AND lockout.expire_time > NOW()
AND lockout.expedition_name = '{}' AND lockout.expedition_name = '{}'
LEFT JOIN expedition_members member LEFT JOIN expedition_members member ON character_data.id = member.character_id
ON character_data.id = member.character_id
AND member.is_current_member = TRUE
WHERE character_data.name IN ({}) WHERE character_data.name IN ({})
ORDER BY character_data.id; ORDER BY character_data.id;
), expedition_name, in_character_names_query); ), expedition_name, in_character_names_query);
@ -420,8 +417,7 @@ uint32_t ExpeditionDatabase::GetExpeditionIDFromCharacterID(uint32_t character_i
uint32_t expedition_id = 0; uint32_t expedition_id = 0;
auto query = fmt::format(SQL( auto query = fmt::format(SQL(
SELECT expedition_id FROM expedition_members SELECT expedition_id FROM expedition_members WHERE character_id = {};
WHERE character_id = {} AND is_current_member = TRUE;
), character_id); ), character_id);
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
@ -641,10 +637,10 @@ void ExpeditionDatabase::InsertMember(uint32_t expedition_id, uint32_t character
auto query = fmt::format(SQL( auto query = fmt::format(SQL(
INSERT INTO expedition_members INSERT INTO expedition_members
(expedition_id, character_id, is_current_member) (expedition_id, character_id)
VALUES VALUES
({}, {}, TRUE) ({}, {})
ON DUPLICATE KEY UPDATE is_current_member = TRUE; ON DUPLICATE KEY UPDATE character_id = VALUES(character_id);
), expedition_id, character_id); ), expedition_id, character_id);
database.QueryDatabase(query); database.QueryDatabase(query);
@ -659,7 +655,7 @@ void ExpeditionDatabase::InsertMembers(
for (const auto& member : members) for (const auto& member : members)
{ {
fmt::format_to(std::back_inserter(insert_values), fmt::format_to(std::back_inserter(insert_values),
"({}, {}, TRUE),", "({}, {}),",
expedition_id, member.char_id expedition_id, member.char_id
); );
} }
@ -669,7 +665,8 @@ void ExpeditionDatabase::InsertMembers(
insert_values.pop_back(); // trailing comma insert_values.pop_back(); // trailing comma
auto query = fmt::format(SQL( auto query = fmt::format(SQL(
INSERT INTO expedition_members (expedition_id, character_id, is_current_member) INSERT INTO expedition_members
(expedition_id, character_id)
VALUES {}; VALUES {};
), insert_values); ), insert_values);
@ -699,25 +696,23 @@ void ExpeditionDatabase::UpdateLockState(uint32_t expedition_id, bool is_locked)
database.QueryDatabase(query); database.QueryDatabase(query);
} }
void ExpeditionDatabase::UpdateMemberRemoved(uint32_t expedition_id, uint32_t character_id) void ExpeditionDatabase::DeleteMember(uint32_t expedition_id, uint32_t character_id)
{ {
LogExpeditionsDetail("Removing member [{}] from expedition [{}]", character_id, expedition_id); LogExpeditionsDetail("Removing member [{}] from expedition [{}]", character_id, expedition_id);
auto query = fmt::format(SQL( auto query = fmt::format(SQL(
UPDATE expedition_members SET is_current_member = FALSE DELETE FROM expedition_members WHERE expedition_id = {} AND character_id = {};
WHERE expedition_id = {} AND character_id = {};
), expedition_id, character_id); ), expedition_id, character_id);
database.QueryDatabase(query); database.QueryDatabase(query);
} }
void ExpeditionDatabase::UpdateAllMembersRemoved(uint32_t expedition_id) void ExpeditionDatabase::DeleteAllMembers(uint32_t expedition_id)
{ {
LogExpeditionsDetail("Updating all members of expedition [{}] as removed", expedition_id); LogExpeditionsDetail("Updating all members of expedition [{}] as removed", expedition_id);
auto query = fmt::format(SQL( auto query = fmt::format(SQL(
UPDATE expedition_members SET is_current_member = FALSE DELETE FROM expedition_members WHERE expedition_id = {};
WHERE expedition_id = {};
), expedition_id); ), expedition_id);
database.QueryDatabase(query); database.QueryDatabase(query);

View File

@ -47,6 +47,8 @@ namespace ExpeditionDatabase
std::vector<ExpeditionLockoutTimer> LoadCharacterLockouts(uint32_t character_id, const std::string& expedition_name); std::vector<ExpeditionLockoutTimer> LoadCharacterLockouts(uint32_t character_id, const std::string& expedition_name);
std::unordered_map<uint32_t, std::unordered_map<std::string, ExpeditionLockoutTimer>> std::unordered_map<uint32_t, std::unordered_map<std::string, ExpeditionLockoutTimer>>
LoadMultipleExpeditionLockouts(const std::vector<uint32_t>& expedition_ids); LoadMultipleExpeditionLockouts(const std::vector<uint32_t>& expedition_ids);
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);
void DeleteAllCharacterLockouts(uint32_t character_id, const std::string& expedition_name); void DeleteAllCharacterLockouts(uint32_t character_id, const std::string& expedition_name);
void DeleteCharacterLockout(uint32_t character_id, const std::string& expedition_name, const std::string& event_name); void DeleteCharacterLockout(uint32_t character_id, const std::string& expedition_name, const std::string& event_name);
@ -69,8 +71,6 @@ namespace ExpeditionDatabase
void InsertMembers(uint32_t expedition_id, const std::vector<ExpeditionMember>& members); void InsertMembers(uint32_t expedition_id, const std::vector<ExpeditionMember>& members);
void UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id); void UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id);
void UpdateLockState(uint32_t expedition_id, bool is_locked); void UpdateLockState(uint32_t expedition_id, bool is_locked);
void UpdateMemberRemoved(uint32_t expedition_id, uint32_t character_id);
void UpdateAllMembersRemoved(uint32_t expedition_id);
void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join); void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join);
}; };
@ -89,7 +89,6 @@ namespace LoadExpeditionColumns
is_locked, is_locked,
leader_name, leader_name,
member_id, member_id,
is_current_member,
member_name member_name
}; };
}; };