Refactor zone expedition caching

This optimizes caching all expeditions by loading dynamic zone data and
expedition members in bulk instead of for each expedition separately.
This reduces the number of queries from 1+2n to 3 total.

Expedition members are now joined in the initial query since empty
expeditions aren't cached anyway. Optional internal lockouts for all
cached expeditions are loaded in a single bulk query afterwards.

Dynamic Zone data is also loaded as a single bulk query afterwards to
simplify processing and keep dz database logic separated. It might be
worth investigating if joining dz data in the initial expeditions load
query is worth refactoring for.
This commit is contained in:
hg 2020-05-30 23:03:01 -04:00
parent f9eafa52f9
commit 2c4f505309
6 changed files with 254 additions and 156 deletions

View File

@ -62,6 +62,42 @@ DynamicZone DynamicZone::LoadDzFromDatabase(uint32_t instance_id)
return dynamic_zone; return dynamic_zone;
} }
std::unordered_map<uint32_t, DynamicZone> DynamicZone::LoadMultipleDzFromDatabase(
const std::vector<uint32_t>& instance_ids)
{
LogDynamicZonesDetail("Loading dynamic zone data for [{}] instances", instance_ids.size());
std::string in_instance_ids_query;
for (const auto& instance_id : instance_ids)
{
fmt::format_to(std::back_inserter(in_instance_ids_query), "{},", instance_id);
}
std::unordered_map<uint32_t, DynamicZone> dynamic_zones;
if (!in_instance_ids_query.empty())
{
in_instance_ids_query.pop_back(); // trailing comma
std::string query = fmt::format(SQL(
{} WHERE dynamic_zones.instance_id IN ({});
), DynamicZoneSelectQuery(), in_instance_ids_query);
auto results = database.QueryDatabase(query);
if (results.Success())
{
for (auto row = results.begin(); row != results.end(); ++row)
{
DynamicZone dz;
dz.LoadDatabaseResult(row);
dynamic_zones.emplace(dz.GetInstanceID(), dz);
}
}
}
return dynamic_zones;
}
uint32_t DynamicZone::CreateInstance() uint32_t DynamicZone::CreateInstance()
{ {
if (m_instance_id) if (m_instance_id)
@ -107,26 +143,11 @@ uint32_t DynamicZone::CreateInstance()
return m_instance_id; return m_instance_id;
} }
void DynamicZone::LoadFromDatabase(uint32_t instance_id) std::string DynamicZone::DynamicZoneSelectQuery()
{ {
if (instance_id == 0) return std::string(SQL(
{
return;
}
if (m_instance_id)
{
LogDynamicZones(
"Loading instance data for [{}] failed, instance id [{}] data already loaded",
instance_id, m_instance_id
);
return;
}
LogDynamicZonesDetail("Loading dz instance [{}] from database", instance_id);
std::string query = fmt::format(SQL(
SELECT SELECT
instance_list.id,
instance_list.zone, instance_list.zone,
instance_list.version, instance_list.version,
instance_list.start_time, instance_list.start_time,
@ -149,36 +170,53 @@ void DynamicZone::LoadFromDatabase(uint32_t instance_id)
dynamic_zones.has_zone_in dynamic_zones.has_zone_in
FROM dynamic_zones FROM dynamic_zones
INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
WHERE dynamic_zones.instance_id = {}; ));
), instance_id); }
void DynamicZone::LoadDatabaseResult(MySQLRequestRow& row)
{
m_instance_id = strtoul(row[0], nullptr, 10);
m_zone_id = strtoul(row[1], nullptr, 10);
m_version = strtoul(row[2], nullptr, 10);
m_start_time = strtoul(row[3], nullptr, 10);
m_duration = strtoul(row[4], nullptr, 10);
m_never_expires = (strtoul(row[5], nullptr, 10) != 0);
m_type = static_cast<DynamicZoneType>(strtoul(row[6], nullptr, 10));
m_expire_time = std::chrono::system_clock::from_time_t(m_start_time + m_duration);
m_compass.zone_id = strtoul(row[7], nullptr, 10);
m_compass.x = strtof(row[8], nullptr);
m_compass.y = strtof(row[9], nullptr);
m_compass.z = strtof(row[10], nullptr);
m_safereturn.zone_id = strtoul(row[11], nullptr, 10);
m_safereturn.x = strtof(row[12], nullptr);
m_safereturn.y = strtof(row[13], nullptr);
m_safereturn.z = strtof(row[14], nullptr);
m_safereturn.heading = strtof(row[15], nullptr);
m_zonein.x = strtof(row[16], nullptr);
m_zonein.y = strtof(row[17], nullptr);
m_zonein.z = strtof(row[18], nullptr);
m_zonein.heading = strtof(row[19], nullptr);
m_has_zonein = (strtoul(row[20], nullptr, 10) != 0);
}
void DynamicZone::LoadFromDatabase(uint32_t instance_id)
{
if (instance_id == 0)
{
return;
}
LogDynamicZonesDetail("Loading dz instance [{}] from database", instance_id);
std::string query = fmt::format(SQL(
{} WHERE dynamic_zones.instance_id = {};
), DynamicZoneSelectQuery(), instance_id);
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if (results.Success() && results.RowCount() > 0) if (results.Success() && results.RowCount() > 0)
{ {
auto row = results.begin(); auto row = results.begin();
LoadDatabaseResult(row);
m_instance_id = instance_id;
m_zone_id = strtoul(row[0], nullptr, 10);
m_version = strtoul(row[1], nullptr, 10);
m_start_time = strtoul(row[2], nullptr, 10);
m_duration = strtoul(row[3], nullptr, 10);
m_never_expires = (strtoul(row[4], nullptr, 10) != 0);
m_type = static_cast<DynamicZoneType>(strtoul(row[5], nullptr, 10));
m_expire_time = std::chrono::system_clock::from_time_t(m_start_time + m_duration);
m_compass.zone_id = strtoul(row[6], nullptr, 10);
m_compass.x = strtof(row[7], nullptr);
m_compass.y = strtof(row[8], nullptr);
m_compass.z = strtof(row[9], nullptr);
m_safereturn.zone_id = strtoul(row[10], nullptr, 10);
m_safereturn.x = strtof(row[11], nullptr);
m_safereturn.y = strtof(row[12], nullptr);
m_safereturn.z = strtof(row[13], nullptr);
m_safereturn.heading = strtof(row[14], nullptr);
m_zonein.x = strtof(row[15], nullptr);
m_zonein.y = strtof(row[16], nullptr);
m_zonein.z = strtof(row[17], nullptr);
m_zonein.heading = strtof(row[18], nullptr);
m_has_zonein = (strtoul(row[19], nullptr, 10) != 0);
} }
} }

View File

@ -24,12 +24,14 @@
#include <chrono> #include <chrono>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
class MySQLRequestRow;
class ServerPacket; class ServerPacket;
enum class DynamicZoneType : uint8_t // DynamicZoneActiveType enum class DynamicZoneType : uint8_t
{ {
None = 0, None = 0,
Expedition, Expedition,
@ -47,7 +49,7 @@ struct DynamicZoneLocation
float z = 0.0f; float z = 0.0f;
float heading = 0.0f; float heading = 0.0f;
DynamicZoneLocation() {} DynamicZoneLocation() = default;
DynamicZoneLocation(uint32_t zone_id_, float x_, float y_, float z_, float heading_) DynamicZoneLocation(uint32_t zone_id_, float x_, float y_, float z_, float heading_)
: zone_id(zone_id_), x(x_), y(y_), z(z_), heading(heading_) {} : zone_id(zone_id_), x(x_), y(y_), z(z_), heading(heading_) {}
}; };
@ -58,9 +60,12 @@ public:
DynamicZone() = default; DynamicZone() = default;
DynamicZone(uint32_t zone_id, uint32_t version, uint32_t duration, DynamicZoneType type); DynamicZone(uint32_t zone_id, uint32_t version, uint32_t duration, DynamicZoneType type);
DynamicZone(std::string zone_shortname, uint32_t version, uint32_t duration, DynamicZoneType type); DynamicZone(std::string zone_shortname, uint32_t version, uint32_t duration, DynamicZoneType type);
DynamicZone(DynamicZoneType type) : m_type(type) { } DynamicZone(uint32_t instance_id) : m_instance_id(instance_id) {}
DynamicZone(DynamicZoneType type) : m_type(type) {}
static DynamicZone LoadDzFromDatabase(uint32_t instance_id); static DynamicZone LoadDzFromDatabase(uint32_t instance_id);
static std::unordered_map<uint32_t, DynamicZone> LoadMultipleDzFromDatabase(
const std::vector<uint32_t>& instance_ids);
static void HandleWorldMessage(ServerPacket* pack); static void HandleWorldMessage(ServerPacket* pack);
DynamicZoneType GetType() const { return m_type; } DynamicZoneType GetType() const { return m_type; }
@ -95,6 +100,8 @@ public:
uint32_t SaveToDatabase(); uint32_t SaveToDatabase();
private: private:
static std::string DynamicZoneSelectQuery();
void LoadDatabaseResult(MySQLRequestRow& row);
void DeleteFromDatabase(); void DeleteFromDatabase();
void SaveCompassToDatabase(); void SaveCompassToDatabase();
void SaveSafeReturnToDatabase(); void SaveSafeReturnToDatabase();
@ -111,7 +118,7 @@ private:
DynamicZoneLocation m_compass; DynamicZoneLocation m_compass;
DynamicZoneLocation m_safereturn; DynamicZoneLocation m_safereturn;
DynamicZoneLocation m_zonein; DynamicZoneLocation m_zonein;
std::chrono::time_point<std::chrono::system_clock> m_expire_time; //uint64_t m_expire_time = 0; std::chrono::time_point<std::chrono::system_clock> m_expire_time;
}; };
#endif #endif

View File

@ -153,58 +153,95 @@ void Expedition::CacheExpeditions(MySQLRequestResult& results)
return; return;
} }
std::vector<uint32_t> expedition_ids;
std::vector<uint32_t> instance_ids;
using col = LoadExpeditionColumns::eLoadExpeditionColumns;
Expedition* current_expedition = nullptr;
uint32_t last_expedition_id = 0; uint32_t last_expedition_id = 0;
for (auto row = results.begin(); row != results.end(); ++row) for (auto row = results.begin(); row != results.end(); ++row)
{ {
auto expedition_id = strtoul(row[0], nullptr, 10); auto expedition_id = strtoul(row[col::id], nullptr, 10);
if (expedition_id != last_expedition_id) if (expedition_id != last_expedition_id)
{ {
auto leader_id = static_cast<uint32_t>(strtoul(row[3], nullptr, 10)); // finished parsing previous expedition members, send member updates
ExpeditionMember leader{ leader_id, row[9] }; // id, name if (current_expedition)
auto instance_id = row[1] ? strtoul(row[1], nullptr, 10) : 0; // can be null from fk constraint {
current_expedition->SendWorldGetOnlineMembers();
current_expedition->SendUpdatesToZoneMembers();
}
DynamicZone dynamic_zone = DynamicZone::LoadDzFromDatabase(instance_id); expedition_ids.emplace_back(expedition_id);
uint32_t leader_id = strtoul(row[col::leader_id], nullptr, 10);
uint32_t instance_id = row[col::instance_id] ? strtoul(row[col::instance_id], nullptr, 10) : 0;
if (instance_id) // can be null from fk constraint
{
instance_ids.emplace_back(instance_id);
}
std::unique_ptr<Expedition> expedition = std::unique_ptr<Expedition>(new Expedition( std::unique_ptr<Expedition> expedition = std::unique_ptr<Expedition>(new Expedition(
expedition_id, expedition_id,
dynamic_zone, DynamicZone{instance_id},
row[2], // expedition name row[col::expedition_name], // expedition name
leader, // expedition leader ExpeditionMember{leader_id, row[col::leader_name]}, // expedition leader id, name
strtoul(row[4], nullptr, 10), // min_players strtoul(row[col::min_players], nullptr, 10), // min_players
strtoul(row[5], nullptr, 10), // max_players strtoul(row[col::max_players], nullptr, 10), // max_players
(strtoul(row[6], nullptr, 10) != 0) // has_replay_timer (strtoul(row[col::has_replay_timer], nullptr, 10) != 0) // has_replay_timer
)); ));
bool add_replay_on_join = (strtoul(row[7], nullptr, 10) != 0); bool add_replay_on_join = (strtoul(row[col::add_replay_on_join], nullptr, 10) != 0);
bool is_locked = (strtoul(row[8], nullptr, 10) != 0); bool is_locked = (strtoul(row[col::is_locked], nullptr, 10) != 0);
expedition->SetReplayLockoutOnMemberJoin(add_replay_on_join); expedition->SetReplayLockoutOnMemberJoin(add_replay_on_join);
expedition->SetLocked(is_locked); expedition->SetLocked(is_locked);
expedition->LoadMembers();
expedition->SendUpdatesToZoneMembers();
// don't bother caching empty expeditions zone->expedition_cache.emplace(expedition_id, std::move(expedition));
if (expedition->GetMemberCount() > 0)
{
zone->expedition_cache.emplace(expedition_id, std::move(expedition));
}
} }
last_expedition_id = expedition_id; last_expedition_id = expedition_id;
// optional lockouts from left join // looping expedition members
if (row[10] && row[11] && row[12] && row[13]) current_expedition = Expedition::FindCachedExpeditionByID(last_expedition_id);
if (current_expedition)
{ {
auto it = zone->expedition_cache.find(last_expedition_id); auto member_id = strtoul(row[col::member_id], nullptr, 10);
if (it != zone->expedition_cache.end()) bool is_current_member = (strtoul(row[col::is_current_member], nullptr, 10) != 0);
current_expedition->AddInternalMember(
row[col::member_name], member_id, ExpeditionMemberStatus::Offline, is_current_member
);
}
}
// update for the last cached expedition
if (current_expedition)
{
current_expedition->SendWorldGetOnlineMembers();
current_expedition->SendUpdatesToZoneMembers();
}
// bulk load dynamic zone data and expedition lockouts for cached expeditions
auto dynamic_zones = DynamicZone::LoadMultipleDzFromDatabase(instance_ids);
auto expedition_lockouts = ExpeditionDatabase::LoadMultipleExpeditionLockouts(expedition_ids);
for (const auto& expedition_id : expedition_ids)
{
auto expedition = Expedition::FindCachedExpeditionByID(expedition_id);
if (expedition)
{
auto dz_iter = dynamic_zones.find(expedition->GetInstanceID());
if (dz_iter != dynamic_zones.end())
{ {
it->second->AddInternalLockout(ExpeditionLockoutTimer{ expedition->m_dynamiczone = dz_iter->second;
row[2], // expedition_name }
row[10], // event_name
strtoull(row[11], nullptr, 10), // expire_time auto lockout_iter = expedition_lockouts.find(expedition->GetID());
static_cast<uint32_t>(strtoul(row[12], nullptr, 10)), // original duration if (lockout_iter != expedition_lockouts.end())
(strtoul(row[13], nullptr, 10) != 0) // is_inherited {
}); expedition->m_lockouts = lockout_iter->second;
} }
} }
} }
@ -257,23 +294,6 @@ bool Expedition::CacheAllFromDatabase()
return true; return true;
} }
void Expedition::LoadMembers()
{
m_members.clear();
auto results = ExpeditionDatabase::LoadExpeditionMembers(m_id);
if (results.Success())
{
for (auto row = results.begin(); row != results.end(); ++row)
{
auto character_id = strtoul(row[0], nullptr, 10);
bool is_current_member = strtoul(row[1], nullptr, 10);
AddInternalMember(row[2], character_id, ExpeditionMemberStatus::Offline, is_current_member);
}
SendWorldGetOnlineMembers();
}
}
void Expedition::SaveLockouts(ExpeditionRequest& request) void Expedition::SaveLockouts(ExpeditionRequest& request)
{ {
m_lockouts = std::move(request).TakeLockouts(); m_lockouts = std::move(request).TakeLockouts();

View File

@ -139,7 +139,6 @@ private:
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 is_current_member = true);
bool ChooseNewLeader(); bool ChooseNewLeader();
bool ConfirmLeaderCommand(Client* requester); bool ConfirmLeaderCommand(Client* requester);
void LoadMembers();
bool ProcessAddConflicts(Client* leader_client, Client* add_client, bool swapping); bool ProcessAddConflicts(Client* leader_client, Client* add_client, bool swapping);
void ProcessLeaderChanged(uint32_t new_leader_id, const std::string& new_leader_name); void ProcessLeaderChanged(uint32_t new_leader_id, const std::string& new_leader_name);
void ProcessLockoutUpdate(const std::string& event_name, uint64_t expire_time, uint32_t duration, bool remove); void ProcessLockoutUpdate(const std::string& event_name, uint64_t expire_time, uint32_t duration, bool remove);

View File

@ -48,11 +48,9 @@ uint32_t ExpeditionDatabase::InsertExpedition(
return results.LastInsertedID(); return results.LastInsertedID();
} }
MySQLRequestResult ExpeditionDatabase::LoadExpedition(uint32_t expedition_id) std::string ExpeditionDatabase::LoadExpeditionsSelectQuery()
{ {
LogExpeditionsDetail("Loading expedition [{}]", expedition_id); return std::string(SQL(
std::string query = fmt::format(SQL(
SELECT SELECT
expedition_details.id, expedition_details.id,
expedition_details.instance_id, expedition_details.instance_id,
@ -64,53 +62,36 @@ MySQLRequestResult ExpeditionDatabase::LoadExpedition(uint32_t expedition_id)
expedition_details.add_replay_on_join, expedition_details.add_replay_on_join,
expedition_details.is_locked, expedition_details.is_locked,
character_data.name leader_name, character_data.name leader_name,
expedition_lockouts.event_name, expedition_members.character_id,
UNIX_TIMESTAMP(expedition_lockouts.expire_time), expedition_members.is_current_member,
expedition_lockouts.duration, member_data.name
expedition_lockouts.is_inherited
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
LEFT JOIN expedition_lockouts INNER JOIN expedition_members ON expedition_details.id = expedition_members.expedition_id
ON expedition_details.id = expedition_lockouts.expedition_id INNER JOIN character_data member_data ON expedition_members.character_id = member_data.id
AND expedition_lockouts.expire_time > NOW() ));
WHERE expedition_details.id = {}; }
), expedition_id);
auto results = database.QueryDatabase(query); MySQLRequestResult ExpeditionDatabase::LoadExpedition(uint32_t expedition_id)
return results; {
LogExpeditionsDetail("Loading expedition [{}]", expedition_id);
std::string query = fmt::format(SQL(
{} WHERE expedition_details.id = {};
), LoadExpeditionsSelectQuery(), expedition_id);
return database.QueryDatabase(query);
} }
MySQLRequestResult ExpeditionDatabase::LoadAllExpeditions() MySQLRequestResult ExpeditionDatabase::LoadAllExpeditions()
{ {
LogExpeditionsDetail("Loading all expeditions from database"); LogExpeditionsDetail("Loading all expeditions from database");
// load all active expeditions and members to current zone cache std::string query = fmt::format(SQL(
std::string query = SQL( {} ORDER BY expedition_details.id;
SELECT ), LoadExpeditionsSelectQuery());
expedition_details.id,
expedition_details.instance_id,
expedition_details.expedition_name,
expedition_details.leader_id,
expedition_details.min_players,
expedition_details.max_players,
expedition_details.has_replay_timer,
expedition_details.add_replay_on_join,
expedition_details.is_locked,
character_data.name leader_name,
expedition_lockouts.event_name,
UNIX_TIMESTAMP(expedition_lockouts.expire_time),
expedition_lockouts.duration,
expedition_lockouts.is_inherited
FROM expedition_details
INNER JOIN character_data ON expedition_details.leader_id = character_data.id
LEFT JOIN expedition_lockouts
ON expedition_details.id = expedition_lockouts.expedition_id
AND expedition_lockouts.expire_time > NOW()
ORDER BY expedition_details.id;
);
auto results = database.QueryDatabase(query); return database.QueryDatabase(query);
return results;
} }
MySQLRequestResult ExpeditionDatabase::LoadCharacterLockouts(uint32_t character_id) MySQLRequestResult ExpeditionDatabase::LoadCharacterLockouts(uint32_t character_id)
@ -151,26 +132,58 @@ MySQLRequestResult ExpeditionDatabase::LoadCharacterLockouts(
return database.QueryDatabase(query); return database.QueryDatabase(query);
} }
MySQLRequestResult ExpeditionDatabase::LoadExpeditionMembers(uint32_t expedition_id) std::unordered_map<uint32_t, std::unordered_map<std::string, ExpeditionLockoutTimer>>
ExpeditionDatabase::LoadMultipleExpeditionLockouts(
const std::vector<uint32_t>& expedition_ids)
{ {
LogExpeditionsDetail("Loading all members for expedition [{}]", expedition_id); LogExpeditionsDetail("Loading internal lockouts for [{}] expeditions", expedition_ids.size());
std::string query = fmt::format(SQL( std::string in_expedition_ids_query;
SELECT for (const auto& expedition_id : expedition_ids)
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
WHERE expedition_id = {};
), expedition_id);
auto results = database.QueryDatabase(query);
if (!results.Success())
{ {
LogExpeditions("Failed to load expedition [{}] members from db", expedition_id); fmt::format_to(std::back_inserter(in_expedition_ids_query), "{},", expedition_id);
} }
return results;
// these are loaded into the same container type expedition's use to store lockouts
std::unordered_map<uint32_t, std::unordered_map<std::string, ExpeditionLockoutTimer>> lockouts;
if (!in_expedition_ids_query.empty())
{
in_expedition_ids_query.pop_back(); // trailing comma
std::string query = fmt::format(SQL(
SELECT
expedition_lockouts.expedition_id,
expedition_lockouts.event_name,
UNIX_TIMESTAMP(expedition_lockouts.expire_time),
expedition_lockouts.duration,
expedition_lockouts.is_inherited,
expedition_details.expedition_name
FROM expedition_lockouts
INNER JOIN expedition_details ON expedition_lockouts.expedition_id = expedition_details.id
WHERE expedition_id IN ({})
ORDER BY expedition_id;
), in_expedition_ids_query);
auto results = database.QueryDatabase(query);
if (results.Success())
{
for (auto row = results.begin(); row != results.end(); ++row)
{
auto expedition_id = strtoul(row[0], nullptr, 10);
lockouts[expedition_id].emplace(row[1], ExpeditionLockoutTimer{
row[5], // expedition_name
row[1], // event_name
strtoull(row[2], nullptr, 10), // expire_time
static_cast<uint32_t>(strtoul(row[3], nullptr, 10)), // original duration
(strtoul(row[4], nullptr, 10) != 0) // is_inherited
});
}
}
}
return lockouts;
} }
MySQLRequestResult ExpeditionDatabase::LoadValidationData( MySQLRequestResult ExpeditionDatabase::LoadValidationData(
@ -200,8 +213,7 @@ MySQLRequestResult ExpeditionDatabase::LoadValidationData(
ORDER BY character_data.id; ORDER BY character_data.id;
), expedition_name, character_names); ), expedition_name, character_names);
auto results = database.QueryDatabase(query); return database.QueryDatabase(query);
return results;
} }
void ExpeditionDatabase::DeleteAllCharacterLockouts(uint32_t character_id) void ExpeditionDatabase::DeleteAllCharacterLockouts(uint32_t character_id)

View File

@ -38,12 +38,14 @@ namespace ExpeditionDatabase
uint32_t InsertExpedition( uint32_t InsertExpedition(
uint32_t instance_id, const std::string& expedition_name, uint32_t leader_id, uint32_t instance_id, const std::string& expedition_name, uint32_t leader_id,
uint32_t min_players, uint32_t max_players, bool has_replay_lockout); uint32_t min_players, uint32_t max_players, bool has_replay_lockout);
std::string LoadExpeditionsSelectQuery();
MySQLRequestResult LoadExpedition(uint32_t expedition_id); MySQLRequestResult LoadExpedition(uint32_t expedition_id);
MySQLRequestResult LoadAllExpeditions(); MySQLRequestResult LoadAllExpeditions();
MySQLRequestResult LoadCharacterLockouts(uint32_t character_id); MySQLRequestResult LoadCharacterLockouts(uint32_t character_id);
MySQLRequestResult LoadCharacterLockouts(uint32_t character_id, const std::string& expedition_name); MySQLRequestResult LoadCharacterLockouts(uint32_t character_id, const std::string& expedition_name);
MySQLRequestResult LoadExpeditionMembers(uint32_t expedition_id);
MySQLRequestResult LoadValidationData(const std::string& character_names_query, const std::string& expedition_name); MySQLRequestResult LoadValidationData(const std::string& character_names_query, const std::string& expedition_name);
std::unordered_map<uint32_t, std::unordered_map<std::string, ExpeditionLockoutTimer>>
LoadMultipleExpeditionLockouts(const std::vector<uint32_t>& expedition_ids);
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);
@ -70,4 +72,24 @@ namespace ExpeditionDatabase
void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join); void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join);
}; };
namespace LoadExpeditionColumns
{
enum eLoadExpeditionColumns
{
id = 0,
instance_id,
expedition_name,
leader_id,
min_players,
max_players,
has_replay_timer,
add_replay_on_join,
is_locked,
leader_name,
member_id,
is_current_member,
member_name
};
};
#endif #endif