mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-15 16:41:29 +00:00
Separate world expedition source files
This commit is contained in:
parent
58b3708a47
commit
0f051b68ae
@ -10,6 +10,9 @@ SET(world_sources
|
|||||||
eql_config.cpp
|
eql_config.cpp
|
||||||
eqemu_api_world_data_service.cpp
|
eqemu_api_world_data_service.cpp
|
||||||
expedition.cpp
|
expedition.cpp
|
||||||
|
expedition_cache.cpp
|
||||||
|
expedition_database.cpp
|
||||||
|
expedition_message.cpp
|
||||||
launcher_link.cpp
|
launcher_link.cpp
|
||||||
launcher_list.cpp
|
launcher_list.cpp
|
||||||
lfplist.cpp
|
lfplist.cpp
|
||||||
@ -41,6 +44,9 @@ SET(world_headers
|
|||||||
eql_config.h
|
eql_config.h
|
||||||
eqemu_api_world_data_service.h
|
eqemu_api_world_data_service.h
|
||||||
expedition.h
|
expedition.h
|
||||||
|
expedition_cache.h
|
||||||
|
expedition_database.h
|
||||||
|
expedition_message.h
|
||||||
launcher_link.h
|
launcher_link.h
|
||||||
launcher_list.h
|
launcher_list.h
|
||||||
lfplist.h
|
lfplist.h
|
||||||
|
|||||||
@ -19,17 +19,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "expedition.h"
|
#include "expedition.h"
|
||||||
#include "clientlist.h"
|
#include "expedition_database.h"
|
||||||
#include "cliententry.h"
|
|
||||||
#include "zonelist.h"
|
#include "zonelist.h"
|
||||||
#include "zoneserver.h"
|
#include "zoneserver.h"
|
||||||
#include "worlddb.h"
|
#include "../common/eqemu_logsys.h"
|
||||||
#include "../common/servertalk.h"
|
|
||||||
#include "../common/string_util.h"
|
|
||||||
|
|
||||||
ExpeditionCache expedition_cache;
|
|
||||||
|
|
||||||
extern ClientList client_list;
|
|
||||||
extern ZSList zoneserver_list;
|
extern ZSList zoneserver_list;
|
||||||
|
|
||||||
Expedition::Expedition(
|
Expedition::Expedition(
|
||||||
@ -120,487 +114,3 @@ void Expedition::CheckExpireWarning()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpeditionCache::LoadActiveExpeditions()
|
|
||||||
{
|
|
||||||
BenchTimer benchmark;
|
|
||||||
|
|
||||||
m_expeditions = ExpeditionDatabase::LoadExpeditions();
|
|
||||||
|
|
||||||
auto elapsed = benchmark.elapsed();
|
|
||||||
LogExpeditions("World caching [{}] expeditions took [{}s]", m_expeditions.size(), elapsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionCache::AddExpedition(uint32_t expedition_id)
|
|
||||||
{
|
|
||||||
if (expedition_id == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto expedition = ExpeditionDatabase::LoadExpedition(expedition_id);
|
|
||||||
|
|
||||||
if (expedition.GetID() == expedition_id)
|
|
||||||
{
|
|
||||||
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
|
||||||
return expedition.GetID() == expedition_id;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (it == m_expeditions.end())
|
|
||||||
{
|
|
||||||
m_expeditions.emplace_back(expedition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionCache::RemoveExpedition(uint32_t expedition_id)
|
|
||||||
{
|
|
||||||
m_expeditions.erase(std::remove_if(m_expeditions.begin(), m_expeditions.end(),
|
|
||||||
[&](const Expedition& expedition) {
|
|
||||||
return expedition.GetID() == expedition_id;
|
|
||||||
}
|
|
||||||
), m_expeditions.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionCache::MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove)
|
|
||||||
{
|
|
||||||
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
|
||||||
return expedition.GetID() == expedition_id;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (it != m_expeditions.end())
|
|
||||||
{
|
|
||||||
if (remove) {
|
|
||||||
it->RemoveMember(character_id);
|
|
||||||
} else {
|
|
||||||
it->AddMember(character_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionCache::RemoveAllMembers(uint32_t expedition_id)
|
|
||||||
{
|
|
||||||
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
|
||||||
return expedition.GetID() == expedition_id;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (it != m_expeditions.end())
|
|
||||||
{
|
|
||||||
it->RemoveAllMembers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionCache::SetSecondsRemaining(uint32_t expedition_id, uint32_t seconds_remaining)
|
|
||||||
{
|
|
||||||
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
|
||||||
return expedition.GetID() == expedition_id;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (it != m_expeditions.end())
|
|
||||||
{
|
|
||||||
it->UpdateDzSecondsRemaining(seconds_remaining);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionCache::Process()
|
|
||||||
{
|
|
||||||
if (!m_process_throttle_timer.Check())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint32_t> expedition_ids;
|
|
||||||
|
|
||||||
// check cache for expired or empty expeditions to delete and notify zones.
|
|
||||||
for (auto it = m_expeditions.begin(); it != m_expeditions.end();)
|
|
||||||
{
|
|
||||||
bool is_deleted = false;
|
|
||||||
|
|
||||||
if (it->IsEmpty() || it->IsExpired())
|
|
||||||
{
|
|
||||||
// don't delete expedition until its dz instance is empty. this prevents
|
|
||||||
// an exploit where all members leave expedition and complete an event
|
|
||||||
// before being kicked from removal timer. the lockout could never be
|
|
||||||
// applied because the zone expedition cache was already invalidated.
|
|
||||||
auto dz_zoneserver = zoneserver_list.FindByInstanceID(it->GetInstanceID());
|
|
||||||
if (!dz_zoneserver || dz_zoneserver->NumPlayers() == 0)
|
|
||||||
{
|
|
||||||
LogExpeditions("Expedition [{}] expired or empty, notifying zones and deleting", it->GetID());
|
|
||||||
expedition_ids.emplace_back(it->GetID());
|
|
||||||
it->SendZonesExpeditionDeleted();
|
|
||||||
is_deleted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it->IsEmpty() && !it->IsPendingDelete() && RuleB(Expedition, EmptyDzShutdownEnabled))
|
|
||||||
{
|
|
||||||
it->UpdateDzSecondsRemaining(RuleI(Expedition, EmptyDzShutdownDelaySeconds));
|
|
||||||
}
|
|
||||||
|
|
||||||
it->SetPendingDelete(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it->CheckExpireWarning();
|
|
||||||
}
|
|
||||||
|
|
||||||
it = is_deleted ? m_expeditions.erase(it) : it + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!expedition_ids.empty())
|
|
||||||
{
|
|
||||||
ExpeditionDatabase::DeleteExpeditions(expedition_ids);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionDatabase::PurgeExpiredExpeditions()
|
|
||||||
{
|
|
||||||
std::string query = SQL(
|
|
||||||
SELECT
|
|
||||||
expedition_details.id
|
|
||||||
FROM expedition_details
|
|
||||||
LEFT JOIN instance_list ON expedition_details.instance_id = instance_list.id
|
|
||||||
LEFT JOIN
|
|
||||||
(
|
|
||||||
SELECT expedition_id, COUNT(*) member_count
|
|
||||||
FROM expedition_members
|
|
||||||
GROUP BY expedition_id
|
|
||||||
) expedition_members
|
|
||||||
ON expedition_members.expedition_id = expedition_details.id
|
|
||||||
WHERE
|
|
||||||
instance_list.id IS NULL
|
|
||||||
OR expedition_members.member_count IS NULL
|
|
||||||
OR (instance_list.start_time + instance_list.duration) <= UNIX_TIMESTAMP();
|
|
||||||
);
|
|
||||||
|
|
||||||
auto results = database.QueryDatabase(query);
|
|
||||||
if (results.Success())
|
|
||||||
{
|
|
||||||
std::vector<uint32_t> expedition_ids;
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row)
|
|
||||||
{
|
|
||||||
expedition_ids.emplace_back(static_cast<uint32_t>(strtoul(row[0], nullptr, 10)));
|
|
||||||
}
|
|
||||||
ExpeditionDatabase::DeleteExpeditions(expedition_ids);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionDatabase::PurgeExpiredCharacterLockouts()
|
|
||||||
{
|
|
||||||
std::string query = SQL(
|
|
||||||
DELETE FROM character_expedition_lockouts
|
|
||||||
WHERE expire_time <= NOW();
|
|
||||||
);
|
|
||||||
|
|
||||||
database.QueryDatabase(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Expedition> ExpeditionDatabase::LoadExpeditions()
|
|
||||||
{
|
|
||||||
std::vector<Expedition> expeditions;
|
|
||||||
|
|
||||||
std::string query = SQL(
|
|
||||||
SELECT
|
|
||||||
expedition_details.id,
|
|
||||||
expedition_details.instance_id,
|
|
||||||
instance_list.zone,
|
|
||||||
instance_list.start_time,
|
|
||||||
instance_list.duration,
|
|
||||||
expedition_members.character_id
|
|
||||||
FROM expedition_details
|
|
||||||
INNER JOIN instance_list ON expedition_details.instance_id = instance_list.id
|
|
||||||
INNER JOIN expedition_members ON expedition_members.expedition_id = expedition_details.id
|
|
||||||
ORDER BY expedition_details.id;
|
|
||||||
);
|
|
||||||
|
|
||||||
auto results = database.QueryDatabase(query);
|
|
||||||
if (results.Success())
|
|
||||||
{
|
|
||||||
uint32_t last_expedition_id = 0;
|
|
||||||
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row)
|
|
||||||
{
|
|
||||||
uint32_t expedition_id = strtoul(row[0], nullptr, 10);
|
|
||||||
|
|
||||||
if (last_expedition_id != expedition_id)
|
|
||||||
{
|
|
||||||
expeditions.emplace_back(
|
|
||||||
static_cast<uint32_t>(strtoul(row[0], nullptr, 10)), // expedition_id
|
|
||||||
static_cast<uint32_t>(strtoul(row[1], nullptr, 10)), // dz_instance_id
|
|
||||||
static_cast<uint32_t>(strtoul(row[2], nullptr, 10)), // dz_zone_id
|
|
||||||
static_cast<uint32_t>(strtoul(row[3], nullptr, 10)), // start_time
|
|
||||||
static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) // duration
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
last_expedition_id = expedition_id;
|
|
||||||
|
|
||||||
uint32_t member_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10));
|
|
||||||
expeditions.back().AddMember(member_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return expeditions;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expedition ExpeditionDatabase::LoadExpedition(uint32_t expedition_id)
|
|
||||||
{
|
|
||||||
LogExpeditions("Loading expedition [{}] for world cache", expedition_id);
|
|
||||||
|
|
||||||
Expedition expedition;
|
|
||||||
|
|
||||||
std::string query = fmt::format(SQL(
|
|
||||||
SELECT
|
|
||||||
expedition_details.id,
|
|
||||||
expedition_details.instance_id,
|
|
||||||
instance_list.zone,
|
|
||||||
instance_list.start_time,
|
|
||||||
instance_list.duration,
|
|
||||||
expedition_members.character_id
|
|
||||||
FROM expedition_details
|
|
||||||
INNER JOIN instance_list ON expedition_details.instance_id = instance_list.id
|
|
||||||
INNER JOIN expedition_members ON expedition_members.expedition_id = expedition_details.id
|
|
||||||
WHERE expedition_details.id = {};
|
|
||||||
), expedition_id);
|
|
||||||
|
|
||||||
auto results = database.QueryDatabase(query);
|
|
||||||
if (results.Success())
|
|
||||||
{
|
|
||||||
bool created = false;
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row)
|
|
||||||
{
|
|
||||||
if (!created)
|
|
||||||
{
|
|
||||||
expedition = Expedition{
|
|
||||||
static_cast<uint32_t>(strtoul(row[0], nullptr, 10)), // expedition_id
|
|
||||||
static_cast<uint32_t>(strtoul(row[1], nullptr, 10)), // dz_instance_id
|
|
||||||
static_cast<uint32_t>(strtoul(row[2], nullptr, 10)), // dz_zone_id
|
|
||||||
static_cast<uint32_t>(strtoul(row[3], nullptr, 10)), // start_time
|
|
||||||
static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) // duration
|
|
||||||
};
|
|
||||||
created = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto member_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10));
|
|
||||||
expedition.AddMember(member_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return expedition;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionDatabase::DeleteExpeditions(const std::vector<uint32_t>& expedition_ids)
|
|
||||||
{
|
|
||||||
LogExpeditionsDetail("Deleting [{}] expedition(s)", expedition_ids.size());
|
|
||||||
|
|
||||||
std::string expedition_ids_query;
|
|
||||||
for (const auto& expedition_id : expedition_ids)
|
|
||||||
{
|
|
||||||
fmt::format_to(std::back_inserter(expedition_ids_query), "{},", expedition_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!expedition_ids_query.empty())
|
|
||||||
{
|
|
||||||
expedition_ids_query.pop_back(); // trailing comma
|
|
||||||
|
|
||||||
std::string query = fmt::format(
|
|
||||||
"DELETE FROM expedition_details 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionDatabase::UpdateDzDuration(uint16_t instance_id, uint32_t new_duration)
|
|
||||||
{
|
|
||||||
std::string query = fmt::format(
|
|
||||||
"UPDATE instance_list SET duration = {} WHERE id = {};",
|
|
||||||
new_duration, instance_id
|
|
||||||
);
|
|
||||||
|
|
||||||
database.QueryDatabase(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionMessage::HandleZoneMessage(ServerPacket* pack)
|
|
||||||
{
|
|
||||||
switch (pack->opcode)
|
|
||||||
{
|
|
||||||
case ServerOP_ExpeditionCreate:
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
|
|
||||||
expedition_cache.AddExpedition(buf->expedition_id);
|
|
||||||
zoneserver_list.SendPacket(pack);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ExpeditionMemberChange:
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerExpeditionMemberChange_Struct*>(pack->pBuffer);
|
|
||||||
expedition_cache.MemberChange(buf->expedition_id, buf->char_id, buf->removed);
|
|
||||||
zoneserver_list.SendPacket(pack);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ExpeditionMemberSwap:
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerExpeditionMemberSwap_Struct*>(pack->pBuffer);
|
|
||||||
expedition_cache.MemberChange(buf->expedition_id, buf->remove_char_id, true);
|
|
||||||
expedition_cache.MemberChange(buf->expedition_id, buf->add_char_id, false);
|
|
||||||
zoneserver_list.SendPacket(pack);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ExpeditionMembersRemoved:
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
|
|
||||||
expedition_cache.RemoveAllMembers(buf->expedition_id);
|
|
||||||
zoneserver_list.SendPacket(pack);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ExpeditionGetOnlineMembers:
|
|
||||||
{
|
|
||||||
ExpeditionMessage::GetOnlineMembers(pack);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ExpeditionDzAddPlayer:
|
|
||||||
{
|
|
||||||
ExpeditionMessage::AddPlayer(pack);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ExpeditionDzMakeLeader:
|
|
||||||
{
|
|
||||||
ExpeditionMessage::MakeLeader(pack);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ExpeditionCharacterLockout:
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerExpeditionCharacterLockout_Struct*>(pack->pBuffer);
|
|
||||||
auto cle = client_list.FindCLEByCharacterID(buf->character_id);
|
|
||||||
if (cle && cle->Server())
|
|
||||||
{
|
|
||||||
cle->Server()->SendPacket(pack);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ExpeditionSaveInvite:
|
|
||||||
{
|
|
||||||
ExpeditionMessage::SaveInvite(pack);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ExpeditionRequestInvite:
|
|
||||||
{
|
|
||||||
ExpeditionMessage::RequestInvite(pack);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ExpeditionSecondsRemaining:
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerExpeditionUpdateDuration_Struct*>(pack->pBuffer);
|
|
||||||
expedition_cache.SetSecondsRemaining(buf->expedition_id, buf->new_duration_seconds);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionMessage::AddPlayer(ServerPacket* pack)
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerDzCommand_Struct*>(pack->pBuffer);
|
|
||||||
|
|
||||||
ClientListEntry* invited_cle = client_list.FindCharacter(buf->target_name);
|
|
||||||
if (invited_cle && invited_cle->Server())
|
|
||||||
{
|
|
||||||
// continue in the add target's zone
|
|
||||||
buf->is_char_online = true;
|
|
||||||
invited_cle->Server()->SendPacket(pack);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// add target not online, return to inviter
|
|
||||||
ClientListEntry* inviter_cle = client_list.FindCharacter(buf->requester_name);
|
|
||||||
if (inviter_cle && inviter_cle->Server())
|
|
||||||
{
|
|
||||||
inviter_cle->Server()->SendPacket(pack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionMessage::MakeLeader(ServerPacket* pack)
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerDzCommand_Struct*>(pack->pBuffer);
|
|
||||||
|
|
||||||
// notify requester (old leader) and new leader of the result
|
|
||||||
ZoneServer* new_leader_zs = nullptr;
|
|
||||||
ClientListEntry* new_leader_cle = client_list.FindCharacter(buf->target_name);
|
|
||||||
if (new_leader_cle && new_leader_cle->Server())
|
|
||||||
{
|
|
||||||
buf->is_char_online = true;
|
|
||||||
new_leader_zs = new_leader_cle->Server();
|
|
||||||
new_leader_zs->SendPacket(pack);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if old and new leader are in the same zone only send one message
|
|
||||||
ClientListEntry* requester_cle = client_list.FindCharacter(buf->requester_name);
|
|
||||||
if (requester_cle && requester_cle->Server() && requester_cle->Server() != new_leader_zs)
|
|
||||||
{
|
|
||||||
requester_cle->Server()->SendPacket(pack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionMessage::GetOnlineMembers(ServerPacket* pack)
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerExpeditionCharacters_Struct*>(pack->pBuffer);
|
|
||||||
|
|
||||||
// not efficient but only requested during caching
|
|
||||||
char zone_name[64] = {0};
|
|
||||||
std::vector<ClientListEntry*> all_clients;
|
|
||||||
all_clients.reserve(client_list.GetClientCount());
|
|
||||||
client_list.GetClients(zone_name, all_clients);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < buf->count; ++i)
|
|
||||||
{
|
|
||||||
auto it = std::find_if(all_clients.begin(), all_clients.end(), [&](const ClientListEntry* cle) {
|
|
||||||
return (cle && cle->CharID() == buf->entries[i].character_id);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (it != all_clients.end())
|
|
||||||
{
|
|
||||||
buf->entries[i].character_zone_id = (*it)->zone();
|
|
||||||
buf->entries[i].character_instance_id = (*it)->instance();
|
|
||||||
buf->entries[i].character_online = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zoneserver_list.SendPacket(buf->sender_zone_id, buf->sender_instance_id, pack);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionMessage::SaveInvite(ServerPacket* pack)
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerDzCommand_Struct*>(pack->pBuffer);
|
|
||||||
|
|
||||||
ClientListEntry* invited_cle = client_list.FindCharacter(buf->target_name);
|
|
||||||
if (invited_cle)
|
|
||||||
{
|
|
||||||
// store packet on cle and re-send it when client requests it
|
|
||||||
buf->is_char_online = true;
|
|
||||||
pack->opcode = ServerOP_ExpeditionDzAddPlayer;
|
|
||||||
invited_cle->SetPendingExpeditionInvite(pack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionMessage::RequestInvite(ServerPacket* pack)
|
|
||||||
{
|
|
||||||
auto buf = reinterpret_cast<ServerExpeditionCharacterID_Struct*>(pack->pBuffer);
|
|
||||||
ClientListEntry* cle = client_list.FindCLEByCharacterID(buf->character_id);
|
|
||||||
if (cle)
|
|
||||||
{
|
|
||||||
auto invite_pack = cle->GetPendingExpeditionInvite();
|
|
||||||
if (invite_pack && cle->Server())
|
|
||||||
{
|
|
||||||
cle->Server()->SendPacket(invite_pack.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -21,59 +21,16 @@
|
|||||||
#ifndef WORLD_EXPEDITION_H
|
#ifndef WORLD_EXPEDITION_H
|
||||||
#define WORLD_EXPEDITION_H
|
#define WORLD_EXPEDITION_H
|
||||||
|
|
||||||
#include "../common/rulesys.h"
|
|
||||||
#include "../common/timer.h"
|
#include "../common/timer.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
extern class ExpeditionCache expedition_cache;
|
|
||||||
|
|
||||||
class Expedition;
|
|
||||||
class ServerPacket;
|
|
||||||
|
|
||||||
namespace ExpeditionDatabase
|
|
||||||
{
|
|
||||||
void PurgeExpiredExpeditions();
|
|
||||||
void PurgeExpiredCharacterLockouts();
|
|
||||||
std::vector<Expedition> LoadExpeditions();
|
|
||||||
Expedition LoadExpedition(uint32_t expedition_id);
|
|
||||||
void DeleteExpeditions(const std::vector<uint32_t>& expedition_ids);
|
|
||||||
void UpdateDzDuration(uint16_t instance_id, uint32_t new_duration);
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace ExpeditionMessage
|
|
||||||
{
|
|
||||||
void HandleZoneMessage(ServerPacket* pack);
|
|
||||||
void AddPlayer(ServerPacket* pack);
|
|
||||||
void MakeLeader(ServerPacket* pack);
|
|
||||||
void GetOnlineMembers(ServerPacket* pack);
|
|
||||||
void SaveInvite(ServerPacket* pack);
|
|
||||||
void RequestInvite(ServerPacket* pack);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpeditionCache
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void AddExpedition(uint32_t expedition_id);
|
|
||||||
void RemoveExpedition(uint32_t expedition_id);
|
|
||||||
void LoadActiveExpeditions();
|
|
||||||
void MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove);
|
|
||||||
void RemoveAllMembers(uint32_t expedition_id);
|
|
||||||
void SetSecondsRemaining(uint32_t expedition_id, uint32_t seconds_remaining);
|
|
||||||
void Process();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Expedition> m_expeditions;
|
|
||||||
Timer m_process_throttle_timer{static_cast<uint32_t>(RuleI(Expedition, WorldExpeditionProcessRateMS))};
|
|
||||||
};
|
|
||||||
|
|
||||||
class Expedition
|
class Expedition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Expedition() = default;
|
Expedition() = default;
|
||||||
Expedition(
|
Expedition(uint32_t expedition_id, uint32_t instance_id, uint32_t dz_zone_id,
|
||||||
uint32_t expedition_id, uint32_t instance_id, uint32_t dz_zone_id,
|
|
||||||
uint32_t expire_time, uint32_t duration);
|
uint32_t expire_time, uint32_t duration);
|
||||||
|
|
||||||
void AddMember(uint32_t character_id) { m_member_ids.emplace(character_id); }
|
void AddMember(uint32_t character_id) { m_member_ids.emplace(character_id); }
|
||||||
|
|||||||
161
world/expedition_cache.cpp
Normal file
161
world/expedition_cache.cpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "expedition_cache.h"
|
||||||
|
#include "expedition.h"
|
||||||
|
#include "expedition_database.h"
|
||||||
|
#include "zonelist.h"
|
||||||
|
#include "zoneserver.h"
|
||||||
|
#include "../common/eqemu_logsys.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
extern ZSList zoneserver_list;
|
||||||
|
|
||||||
|
ExpeditionCache expedition_cache;
|
||||||
|
|
||||||
|
void ExpeditionCache::LoadActiveExpeditions()
|
||||||
|
{
|
||||||
|
BenchTimer benchmark;
|
||||||
|
|
||||||
|
m_expeditions = ExpeditionDatabase::LoadExpeditions();
|
||||||
|
|
||||||
|
auto elapsed = benchmark.elapsed();
|
||||||
|
LogExpeditions("World caching [{}] expeditions took [{}s]", m_expeditions.size(), elapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionCache::AddExpedition(uint32_t expedition_id)
|
||||||
|
{
|
||||||
|
if (expedition_id == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto expedition = ExpeditionDatabase::LoadExpedition(expedition_id);
|
||||||
|
|
||||||
|
if (expedition.GetID() == expedition_id)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
||||||
|
return expedition.GetID() == expedition_id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it == m_expeditions.end())
|
||||||
|
{
|
||||||
|
m_expeditions.emplace_back(expedition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionCache::RemoveExpedition(uint32_t expedition_id)
|
||||||
|
{
|
||||||
|
m_expeditions.erase(std::remove_if(m_expeditions.begin(), m_expeditions.end(),
|
||||||
|
[&](const Expedition& expedition) {
|
||||||
|
return expedition.GetID() == expedition_id;
|
||||||
|
}
|
||||||
|
), m_expeditions.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionCache::MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
||||||
|
return expedition.GetID() == expedition_id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it != m_expeditions.end())
|
||||||
|
{
|
||||||
|
if (remove) {
|
||||||
|
it->RemoveMember(character_id);
|
||||||
|
} else {
|
||||||
|
it->AddMember(character_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionCache::RemoveAllMembers(uint32_t expedition_id)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
||||||
|
return expedition.GetID() == expedition_id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it != m_expeditions.end())
|
||||||
|
{
|
||||||
|
it->RemoveAllMembers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionCache::SetSecondsRemaining(uint32_t expedition_id, uint32_t seconds_remaining)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
||||||
|
return expedition.GetID() == expedition_id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it != m_expeditions.end())
|
||||||
|
{
|
||||||
|
it->UpdateDzSecondsRemaining(seconds_remaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionCache::Process()
|
||||||
|
{
|
||||||
|
if (!m_process_throttle_timer.Check())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t> expedition_ids;
|
||||||
|
|
||||||
|
for (auto it = m_expeditions.begin(); it != m_expeditions.end();)
|
||||||
|
{
|
||||||
|
bool is_deleted = false;
|
||||||
|
|
||||||
|
if (it->IsEmpty() || it->IsExpired())
|
||||||
|
{
|
||||||
|
// don't delete expedition until its dz instance is empty. this prevents
|
||||||
|
// an exploit where all members leave expedition and complete an event
|
||||||
|
// before being kicked from removal timer. the lockout could never be
|
||||||
|
// applied because the zone expedition cache was already invalidated.
|
||||||
|
auto dz_zoneserver = zoneserver_list.FindByInstanceID(it->GetInstanceID());
|
||||||
|
if (!dz_zoneserver || dz_zoneserver->NumPlayers() == 0)
|
||||||
|
{
|
||||||
|
LogExpeditions("Expedition [{}] expired or empty, notifying zones and deleting", it->GetID());
|
||||||
|
expedition_ids.emplace_back(it->GetID());
|
||||||
|
it->SendZonesExpeditionDeleted();
|
||||||
|
is_deleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it->IsEmpty() && !it->IsPendingDelete() && RuleB(Expedition, EmptyDzShutdownEnabled))
|
||||||
|
{
|
||||||
|
it->UpdateDzSecondsRemaining(RuleI(Expedition, EmptyDzShutdownDelaySeconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
it->SetPendingDelete(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
it->CheckExpireWarning();
|
||||||
|
}
|
||||||
|
|
||||||
|
it = is_deleted ? m_expeditions.erase(it) : it + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expedition_ids.empty())
|
||||||
|
{
|
||||||
|
ExpeditionDatabase::DeleteExpeditions(expedition_ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
49
world/expedition_cache.h
Normal file
49
world/expedition_cache.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* 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 WORLD_EXPEDITION_CACHE_H
|
||||||
|
#define WORLD_EXPEDITION_CACHE_H
|
||||||
|
|
||||||
|
#include "../common/rulesys.h"
|
||||||
|
#include "../common/timer.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
extern class ExpeditionCache expedition_cache;
|
||||||
|
|
||||||
|
class Expedition;
|
||||||
|
|
||||||
|
class ExpeditionCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void AddExpedition(uint32_t expedition_id);
|
||||||
|
void LoadActiveExpeditions();
|
||||||
|
void MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove);
|
||||||
|
void Process();
|
||||||
|
void RemoveAllMembers(uint32_t expedition_id);
|
||||||
|
void RemoveExpedition(uint32_t expedition_id);
|
||||||
|
void SetSecondsRemaining(uint32_t expedition_id, uint32_t seconds_remaining);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Expedition> m_expeditions;
|
||||||
|
Timer m_process_throttle_timer{static_cast<uint32_t>(RuleI(Expedition, WorldExpeditionProcessRateMS))};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
200
world/expedition_database.cpp
Normal file
200
world/expedition_database.cpp
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "expedition_database.h"
|
||||||
|
#include "expedition.h"
|
||||||
|
#include "worlddb.h"
|
||||||
|
|
||||||
|
void ExpeditionDatabase::PurgeExpiredExpeditions()
|
||||||
|
{
|
||||||
|
std::string query = SQL(
|
||||||
|
SELECT
|
||||||
|
expedition_details.id
|
||||||
|
FROM expedition_details
|
||||||
|
LEFT JOIN instance_list ON expedition_details.instance_id = instance_list.id
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
SELECT expedition_id, COUNT(*) member_count
|
||||||
|
FROM expedition_members
|
||||||
|
GROUP BY expedition_id
|
||||||
|
) expedition_members
|
||||||
|
ON expedition_members.expedition_id = expedition_details.id
|
||||||
|
WHERE
|
||||||
|
instance_list.id IS NULL
|
||||||
|
OR expedition_members.member_count IS NULL
|
||||||
|
OR (instance_list.start_time + instance_list.duration) <= UNIX_TIMESTAMP();
|
||||||
|
);
|
||||||
|
|
||||||
|
auto results = database.QueryDatabase(query);
|
||||||
|
if (results.Success())
|
||||||
|
{
|
||||||
|
std::vector<uint32_t> expedition_ids;
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row)
|
||||||
|
{
|
||||||
|
expedition_ids.emplace_back(static_cast<uint32_t>(strtoul(row[0], nullptr, 10)));
|
||||||
|
}
|
||||||
|
ExpeditionDatabase::DeleteExpeditions(expedition_ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionDatabase::PurgeExpiredCharacterLockouts()
|
||||||
|
{
|
||||||
|
std::string query = SQL(
|
||||||
|
DELETE FROM character_expedition_lockouts
|
||||||
|
WHERE expire_time <= NOW();
|
||||||
|
);
|
||||||
|
|
||||||
|
database.QueryDatabase(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Expedition> ExpeditionDatabase::LoadExpeditions()
|
||||||
|
{
|
||||||
|
std::vector<Expedition> expeditions;
|
||||||
|
|
||||||
|
std::string query = SQL(
|
||||||
|
SELECT
|
||||||
|
expedition_details.id,
|
||||||
|
expedition_details.instance_id,
|
||||||
|
instance_list.zone,
|
||||||
|
instance_list.start_time,
|
||||||
|
instance_list.duration,
|
||||||
|
expedition_members.character_id
|
||||||
|
FROM expedition_details
|
||||||
|
INNER JOIN instance_list ON expedition_details.instance_id = instance_list.id
|
||||||
|
INNER JOIN expedition_members ON expedition_members.expedition_id = expedition_details.id
|
||||||
|
ORDER BY expedition_details.id;
|
||||||
|
);
|
||||||
|
|
||||||
|
auto results = database.QueryDatabase(query);
|
||||||
|
if (results.Success())
|
||||||
|
{
|
||||||
|
uint32_t last_expedition_id = 0;
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row)
|
||||||
|
{
|
||||||
|
uint32_t expedition_id = strtoul(row[0], nullptr, 10);
|
||||||
|
|
||||||
|
if (last_expedition_id != expedition_id)
|
||||||
|
{
|
||||||
|
expeditions.emplace_back(
|
||||||
|
static_cast<uint32_t>(strtoul(row[0], nullptr, 10)), // expedition_id
|
||||||
|
static_cast<uint32_t>(strtoul(row[1], nullptr, 10)), // dz_instance_id
|
||||||
|
static_cast<uint32_t>(strtoul(row[2], nullptr, 10)), // dz_zone_id
|
||||||
|
static_cast<uint32_t>(strtoul(row[3], nullptr, 10)), // start_time
|
||||||
|
static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) // duration
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_expedition_id = expedition_id;
|
||||||
|
|
||||||
|
uint32_t member_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10));
|
||||||
|
expeditions.back().AddMember(member_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expeditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expedition ExpeditionDatabase::LoadExpedition(uint32_t expedition_id)
|
||||||
|
{
|
||||||
|
LogExpeditions("Loading expedition [{}] for world cache", expedition_id);
|
||||||
|
|
||||||
|
Expedition expedition;
|
||||||
|
|
||||||
|
std::string query = fmt::format(SQL(
|
||||||
|
SELECT
|
||||||
|
expedition_details.id,
|
||||||
|
expedition_details.instance_id,
|
||||||
|
instance_list.zone,
|
||||||
|
instance_list.start_time,
|
||||||
|
instance_list.duration,
|
||||||
|
expedition_members.character_id
|
||||||
|
FROM expedition_details
|
||||||
|
INNER JOIN instance_list ON expedition_details.instance_id = instance_list.id
|
||||||
|
INNER JOIN expedition_members ON expedition_members.expedition_id = expedition_details.id
|
||||||
|
WHERE expedition_details.id = {};
|
||||||
|
), expedition_id);
|
||||||
|
|
||||||
|
auto results = database.QueryDatabase(query);
|
||||||
|
if (results.Success())
|
||||||
|
{
|
||||||
|
bool created = false;
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row)
|
||||||
|
{
|
||||||
|
if (!created)
|
||||||
|
{
|
||||||
|
expedition = Expedition{
|
||||||
|
static_cast<uint32_t>(strtoul(row[0], nullptr, 10)), // expedition_id
|
||||||
|
static_cast<uint32_t>(strtoul(row[1], nullptr, 10)), // dz_instance_id
|
||||||
|
static_cast<uint32_t>(strtoul(row[2], nullptr, 10)), // dz_zone_id
|
||||||
|
static_cast<uint32_t>(strtoul(row[3], nullptr, 10)), // start_time
|
||||||
|
static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) // duration
|
||||||
|
};
|
||||||
|
created = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto member_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10));
|
||||||
|
expedition.AddMember(member_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expedition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionDatabase::DeleteExpeditions(const std::vector<uint32_t>& expedition_ids)
|
||||||
|
{
|
||||||
|
LogExpeditionsDetail("Deleting [{}] expedition(s)", expedition_ids.size());
|
||||||
|
|
||||||
|
std::string expedition_ids_query;
|
||||||
|
for (const auto& expedition_id : expedition_ids)
|
||||||
|
{
|
||||||
|
fmt::format_to(std::back_inserter(expedition_ids_query), "{},", expedition_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expedition_ids_query.empty())
|
||||||
|
{
|
||||||
|
expedition_ids_query.pop_back(); // trailing comma
|
||||||
|
|
||||||
|
std::string query = fmt::format(
|
||||||
|
"DELETE FROM expedition_details 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionDatabase::UpdateDzDuration(uint16_t instance_id, uint32_t new_duration)
|
||||||
|
{
|
||||||
|
std::string query = fmt::format(
|
||||||
|
"UPDATE instance_list SET duration = {} WHERE id = {};",
|
||||||
|
new_duration, instance_id
|
||||||
|
);
|
||||||
|
|
||||||
|
database.QueryDatabase(query);
|
||||||
|
}
|
||||||
39
world/expedition_database.h
Normal file
39
world/expedition_database.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* 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 WORLD_EXPEDITION_DATABASE_H
|
||||||
|
#define WORLD_EXPEDITION_DATABASE_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Expedition;
|
||||||
|
|
||||||
|
namespace ExpeditionDatabase
|
||||||
|
{
|
||||||
|
void DeleteExpeditions(const std::vector<uint32_t>& expedition_ids);
|
||||||
|
std::vector<Expedition> LoadExpeditions();
|
||||||
|
Expedition LoadExpedition(uint32_t expedition_id);
|
||||||
|
void PurgeExpiredExpeditions();
|
||||||
|
void PurgeExpiredCharacterLockouts();
|
||||||
|
void UpdateDzDuration(uint16_t instance_id, uint32_t new_duration);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
207
world/expedition_message.cpp
Normal file
207
world/expedition_message.cpp
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "expedition_message.h"
|
||||||
|
#include "expedition_cache.h"
|
||||||
|
#include "cliententry.h"
|
||||||
|
#include "clientlist.h"
|
||||||
|
#include "zonelist.h"
|
||||||
|
#include "zoneserver.h"
|
||||||
|
#include "../common/servertalk.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
extern ClientList client_list;
|
||||||
|
extern ZSList zoneserver_list;
|
||||||
|
|
||||||
|
void ExpeditionMessage::HandleZoneMessage(ServerPacket* pack)
|
||||||
|
{
|
||||||
|
switch (pack->opcode)
|
||||||
|
{
|
||||||
|
case ServerOP_ExpeditionCreate:
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
|
||||||
|
expedition_cache.AddExpedition(buf->expedition_id);
|
||||||
|
zoneserver_list.SendPacket(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_ExpeditionMemberChange:
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerExpeditionMemberChange_Struct*>(pack->pBuffer);
|
||||||
|
expedition_cache.MemberChange(buf->expedition_id, buf->char_id, buf->removed);
|
||||||
|
zoneserver_list.SendPacket(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_ExpeditionMemberSwap:
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerExpeditionMemberSwap_Struct*>(pack->pBuffer);
|
||||||
|
expedition_cache.MemberChange(buf->expedition_id, buf->remove_char_id, true);
|
||||||
|
expedition_cache.MemberChange(buf->expedition_id, buf->add_char_id, false);
|
||||||
|
zoneserver_list.SendPacket(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_ExpeditionMembersRemoved:
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
|
||||||
|
expedition_cache.RemoveAllMembers(buf->expedition_id);
|
||||||
|
zoneserver_list.SendPacket(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_ExpeditionGetOnlineMembers:
|
||||||
|
{
|
||||||
|
ExpeditionMessage::GetOnlineMembers(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_ExpeditionDzAddPlayer:
|
||||||
|
{
|
||||||
|
ExpeditionMessage::AddPlayer(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_ExpeditionDzMakeLeader:
|
||||||
|
{
|
||||||
|
ExpeditionMessage::MakeLeader(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_ExpeditionCharacterLockout:
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerExpeditionCharacterLockout_Struct*>(pack->pBuffer);
|
||||||
|
auto cle = client_list.FindCLEByCharacterID(buf->character_id);
|
||||||
|
if (cle && cle->Server())
|
||||||
|
{
|
||||||
|
cle->Server()->SendPacket(pack);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_ExpeditionSaveInvite:
|
||||||
|
{
|
||||||
|
ExpeditionMessage::SaveInvite(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_ExpeditionRequestInvite:
|
||||||
|
{
|
||||||
|
ExpeditionMessage::RequestInvite(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_ExpeditionSecondsRemaining:
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerExpeditionUpdateDuration_Struct*>(pack->pBuffer);
|
||||||
|
expedition_cache.SetSecondsRemaining(buf->expedition_id, buf->new_duration_seconds);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionMessage::AddPlayer(ServerPacket* pack)
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerDzCommand_Struct*>(pack->pBuffer);
|
||||||
|
|
||||||
|
ClientListEntry* invited_cle = client_list.FindCharacter(buf->target_name);
|
||||||
|
if (invited_cle && invited_cle->Server())
|
||||||
|
{
|
||||||
|
// continue in the add target's zone
|
||||||
|
buf->is_char_online = true;
|
||||||
|
invited_cle->Server()->SendPacket(pack);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// add target not online, return to inviter
|
||||||
|
ClientListEntry* inviter_cle = client_list.FindCharacter(buf->requester_name);
|
||||||
|
if (inviter_cle && inviter_cle->Server())
|
||||||
|
{
|
||||||
|
inviter_cle->Server()->SendPacket(pack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionMessage::MakeLeader(ServerPacket* pack)
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerDzCommand_Struct*>(pack->pBuffer);
|
||||||
|
|
||||||
|
// notify requester (old leader) and new leader of the result
|
||||||
|
ZoneServer* new_leader_zs = nullptr;
|
||||||
|
ClientListEntry* new_leader_cle = client_list.FindCharacter(buf->target_name);
|
||||||
|
if (new_leader_cle && new_leader_cle->Server())
|
||||||
|
{
|
||||||
|
buf->is_char_online = true;
|
||||||
|
new_leader_zs = new_leader_cle->Server();
|
||||||
|
new_leader_zs->SendPacket(pack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if old and new leader are in the same zone only send one message
|
||||||
|
ClientListEntry* requester_cle = client_list.FindCharacter(buf->requester_name);
|
||||||
|
if (requester_cle && requester_cle->Server() && requester_cle->Server() != new_leader_zs)
|
||||||
|
{
|
||||||
|
requester_cle->Server()->SendPacket(pack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionMessage::GetOnlineMembers(ServerPacket* pack)
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerExpeditionCharacters_Struct*>(pack->pBuffer);
|
||||||
|
|
||||||
|
// not efficient but only requested during caching
|
||||||
|
char zone_name[64] = {0};
|
||||||
|
std::vector<ClientListEntry*> all_clients;
|
||||||
|
all_clients.reserve(client_list.GetClientCount());
|
||||||
|
client_list.GetClients(zone_name, all_clients);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < buf->count; ++i)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(all_clients.begin(), all_clients.end(), [&](const ClientListEntry* cle) {
|
||||||
|
return (cle && cle->CharID() == buf->entries[i].character_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it != all_clients.end())
|
||||||
|
{
|
||||||
|
buf->entries[i].character_zone_id = (*it)->zone();
|
||||||
|
buf->entries[i].character_instance_id = (*it)->instance();
|
||||||
|
buf->entries[i].character_online = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zoneserver_list.SendPacket(buf->sender_zone_id, buf->sender_instance_id, pack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionMessage::SaveInvite(ServerPacket* pack)
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerDzCommand_Struct*>(pack->pBuffer);
|
||||||
|
|
||||||
|
ClientListEntry* invited_cle = client_list.FindCharacter(buf->target_name);
|
||||||
|
if (invited_cle)
|
||||||
|
{
|
||||||
|
// store packet on cle and re-send it when client requests it
|
||||||
|
buf->is_char_online = true;
|
||||||
|
pack->opcode = ServerOP_ExpeditionDzAddPlayer;
|
||||||
|
invited_cle->SetPendingExpeditionInvite(pack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpeditionMessage::RequestInvite(ServerPacket* pack)
|
||||||
|
{
|
||||||
|
auto buf = reinterpret_cast<ServerExpeditionCharacterID_Struct*>(pack->pBuffer);
|
||||||
|
ClientListEntry* cle = client_list.FindCLEByCharacterID(buf->character_id);
|
||||||
|
if (cle)
|
||||||
|
{
|
||||||
|
auto invite_pack = cle->GetPendingExpeditionInvite();
|
||||||
|
if (invite_pack && cle->Server())
|
||||||
|
{
|
||||||
|
cle->Server()->SendPacket(invite_pack.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
world/expedition_message.h
Normal file
36
world/expedition_message.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* 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 WORLD_EXPEDITION_MESSAGE_H
|
||||||
|
#define WORLD_EXPEDITION_MESSAGE_H
|
||||||
|
|
||||||
|
class ServerPacket;
|
||||||
|
|
||||||
|
namespace ExpeditionMessage
|
||||||
|
{
|
||||||
|
void AddPlayer(ServerPacket* pack);
|
||||||
|
void GetOnlineMembers(ServerPacket* pack);
|
||||||
|
void HandleZoneMessage(ServerPacket* pack);
|
||||||
|
void MakeLeader(ServerPacket* pack);
|
||||||
|
void RequestInvite(ServerPacket* pack);
|
||||||
|
void SaveInvite(ServerPacket* pack);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -88,7 +88,8 @@ union semun {
|
|||||||
#include "queryserv.h"
|
#include "queryserv.h"
|
||||||
#include "web_interface.h"
|
#include "web_interface.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "expedition.h"
|
#include "expedition_cache.h"
|
||||||
|
#include "expedition_database.h"
|
||||||
|
|
||||||
#include "../common/net/servertalk_server.h"
|
#include "../common/net/servertalk_server.h"
|
||||||
#include "../zone/data_bucket.h"
|
#include "../zone/data_bucket.h"
|
||||||
|
|||||||
@ -36,7 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "ucs.h"
|
#include "ucs.h"
|
||||||
#include "queryserv.h"
|
#include "queryserv.h"
|
||||||
#include "world_store.h"
|
#include "world_store.h"
|
||||||
#include "expedition.h"
|
#include "expedition_message.h"
|
||||||
|
|
||||||
extern ClientList client_list;
|
extern ClientList client_list;
|
||||||
extern GroupLFPList LFPGroupList;
|
extern GroupLFPList LFPGroupList;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user