diff --git a/utils/sql/git/required/wip_expeditions.sql b/utils/sql/git/required/wip_expeditions.sql index 5524a2919..a51d07095 100644 --- a/utils/sql/git/required/wip_expeditions.sql +++ b/utils/sql/git/required/wip_expeditions.sql @@ -33,6 +33,7 @@ CREATE TABLE `expedition_members` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `expedition_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 INDEX `expedition_id_character_id` (`expedition_id`, `character_id`) ) diff --git a/world/expedition_database.cpp b/world/expedition_database.cpp index e3755befb..f9df67918 100644 --- a/world/expedition_database.cpp +++ b/world/expedition_database.cpp @@ -32,7 +32,7 @@ void ExpeditionDatabase::PurgeExpiredExpeditions() LEFT JOIN instance_list ON dynamic_zones.instance_id = instance_list.id LEFT JOIN ( - SELECT expedition_id, COUNT(*) member_count + SELECT expedition_id, COUNT(IF(is_current_member = TRUE, 1, NULL)) member_count FROM expedition_members GROUP BY expedition_id ) expedition_members @@ -40,6 +40,7 @@ void ExpeditionDatabase::PurgeExpiredExpeditions() WHERE instance_list.id IS NULL OR expedition_members.member_count IS NULL + OR expedition_members.member_count = 0 OR (instance_list.start_time + instance_list.duration) <= UNIX_TIMESTAMP(); ); @@ -51,7 +52,12 @@ void ExpeditionDatabase::PurgeExpiredExpeditions() { expedition_ids.emplace_back(static_cast(strtoul(row[0], nullptr, 10))); } - ExpeditionDatabase::DeleteExpeditions(expedition_ids); + + if (!expedition_ids.empty()) + { + ExpeditionDatabase::MoveMembersToSafeReturn(expedition_ids); + ExpeditionDatabase::DeleteExpeditions(expedition_ids); + } } } @@ -83,6 +89,7 @@ std::vector ExpeditionDatabase::LoadExpeditions(uint32_t select_expe INNER JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id INNER JOIN expedition_members ON expedition_members.expedition_id = expeditions.id + AND expedition_members.is_current_member = TRUE ); if (select_expedition_id != 0) @@ -180,3 +187,29 @@ void ExpeditionDatabase::UpdateLeaderID(uint32_t expedition_id, uint32_t leader_ database.QueryDatabase(query); } + +void ExpeditionDatabase::MoveMembersToSafeReturn(const std::vector& expedition_ids) +{ + LogExpeditionsDetail("Moving members from [{}] expedition(s) to safereturn", expedition_ids.size()); + + // 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_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 + AND character_data.zone_id = instance_list.zone + SET + zone_id = IF(safe_return_zone_id > 0, safe_return_zone_id, zone_id), + zone_instance = IF(safe_return_zone_id > 0, 0, zone_instance), + x = IF(safe_return_zone_id > 0, safe_return_x, x), + y = IF(safe_return_zone_id > 0, safe_return_y, y), + z = IF(safe_return_zone_id > 0, safe_return_z, z), + heading = IF(safe_return_zone_id > 0, safe_return_heading, heading) + WHERE expeditions.id IN ({}); + ), fmt::join(expedition_ids, ",")); + + database.QueryDatabase(query); +} diff --git a/world/expedition_database.h b/world/expedition_database.h index 302dba3e2..16341210c 100644 --- a/world/expedition_database.h +++ b/world/expedition_database.h @@ -31,6 +31,7 @@ namespace ExpeditionDatabase void DeleteExpeditions(const std::vector& expedition_ids); std::vector LoadExpeditions(uint32_t select_expedition_id = 0); Expedition LoadExpedition(uint32_t expedition_id); + void MoveMembersToSafeReturn(const std::vector& expedition_ids); void PurgeExpiredExpeditions(); void PurgeExpiredCharacterLockouts(); void UpdateDzDuration(uint16_t instance_id, uint32_t new_duration); diff --git a/world/expedition_state.cpp b/world/expedition_state.cpp index df09a5f2f..332231f1b 100644 --- a/world/expedition_state.cpp +++ b/world/expedition_state.cpp @@ -152,6 +152,7 @@ void ExpeditionState::Process() if (!expedition_ids.empty()) { + ExpeditionDatabase::MoveMembersToSafeReturn(expedition_ids); ExpeditionDatabase::DeleteExpeditions(expedition_ids); } } diff --git a/world/main.cpp b/world/main.cpp index 01682b26a..b426d13ff 100644 --- a/world/main.cpp +++ b/world/main.cpp @@ -425,16 +425,16 @@ int main(int argc, char** argv) { adventure_manager.LoadLeaderboardInfo(); + LogInfo("Purging expired expeditions"); + ExpeditionDatabase::PurgeExpiredExpeditions(); + ExpeditionDatabase::PurgeExpiredCharacterLockouts(); + LogInfo("Purging expired instances"); database.PurgeExpiredInstances(); Timer PurgeInstanceTimer(450000); PurgeInstanceTimer.Start(450000); - LogInfo("Purging expired expeditions"); - ExpeditionDatabase::PurgeExpiredExpeditions(); - ExpeditionDatabase::PurgeExpiredCharacterLockouts(); - LogInfo("Loading active expeditions"); expedition_state.LoadActiveExpeditions(); diff --git a/zone/expedition_database.cpp b/zone/expedition_database.cpp index 69a1ebfa7..7d1fd7a3c 100644 --- a/zone/expedition_database.cpp +++ b/zone/expedition_database.cpp @@ -70,6 +70,7 @@ std::string ExpeditionDatabase::LoadExpeditionsSelectQuery() FROM expeditions INNER JOIN character_data ON expeditions.leader_id = character_data.id INNER JOIN expedition_members ON expeditions.id = expedition_members.expedition_id + AND expedition_members.is_current_member = TRUE INNER JOIN character_data member_data ON expedition_members.character_id = member_data.id )); } @@ -251,7 +252,9 @@ MySQLRequestResult ExpeditionDatabase::LoadMembersForCreateRequest( ON character_data.id = lockout.character_id AND lockout.expire_time > NOW() AND lockout.expedition_name = '{}' - LEFT JOIN expedition_members member ON character_data.id = member.character_id + 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 FIELD(character_data.name, {}) ), EscapeString(expedition_name), in_character_names_query, in_character_names_query); @@ -357,7 +360,8 @@ uint32_t ExpeditionDatabase::GetExpeditionIDFromCharacterID(uint32_t character_i uint32_t expedition_id = 0; auto query = fmt::format(SQL( - SELECT expedition_id FROM expedition_members WHERE character_id = {}; + SELECT expedition_id FROM expedition_members + WHERE character_id = {} AND is_current_member = TRUE; ), character_id); auto results = database.QueryDatabase(query); @@ -519,7 +523,7 @@ void ExpeditionDatabase::InsertMember(uint32_t expedition_id, uint32_t character (expedition_id, character_id) VALUES ({}, {}) - ON DUPLICATE KEY UPDATE character_id = VALUES(character_id); + ON DUPLICATE KEY UPDATE is_current_member = TRUE; ), expedition_id, character_id); database.QueryDatabase(query); @@ -546,7 +550,8 @@ void ExpeditionDatabase::InsertMembers( auto query = fmt::format(SQL( INSERT INTO expedition_members (expedition_id, character_id) - VALUES {}; + VALUES {} + ON DUPLICATE KEY UPDATE is_current_member = TRUE; ), insert_values); database.QueryDatabase(query); @@ -569,7 +574,8 @@ void ExpeditionDatabase::DeleteMember(uint32_t expedition_id, uint32_t character LogExpeditionsDetail("Removing member [{}] from expedition [{}]", character_id, expedition_id); auto query = fmt::format(SQL( - DELETE FROM expedition_members WHERE expedition_id = {} AND character_id = {}; + UPDATE expedition_members SET is_current_member = FALSE + WHERE expedition_id = {} AND character_id = {}; ), expedition_id, character_id); database.QueryDatabase(query); @@ -577,10 +583,10 @@ void ExpeditionDatabase::DeleteMember(uint32_t expedition_id, uint32_t character void ExpeditionDatabase::DeleteAllMembers(uint32_t expedition_id) { - LogExpeditionsDetail("Updating all members of expedition [{}] as removed", expedition_id); + LogExpeditionsDetail("Removing all members of expedition [{}]", expedition_id); auto query = fmt::format(SQL( - DELETE FROM expedition_members WHERE expedition_id = {}; + UPDATE expedition_members SET is_current_member = FALSE WHERE expedition_id = {}; ), expedition_id); database.QueryDatabase(query);