mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 09:31:30 +00:00
This allows shared tasks to create dz instances automatically through the `dz_template_id` field instead of using quest scripts. Quest apis were also added to create expeditions from template ids.
177 lines
5.3 KiB
C++
177 lines
5.3 KiB
C++
#include "dynamic_zone_manager.h"
|
|
#include "dynamic_zone.h"
|
|
#include "worlddb.h"
|
|
#include "zonelist.h"
|
|
#include "zoneserver.h"
|
|
#include "../common/rulesys.h"
|
|
#include "../common/repositories/expeditions_repository.h"
|
|
#include "../common/repositories/expedition_lockouts_repository.h"
|
|
|
|
extern ZSList zoneserver_list;
|
|
|
|
DynamicZoneManager dynamic_zone_manager;
|
|
|
|
DynamicZoneManager::DynamicZoneManager() :
|
|
m_process_throttle_timer{ static_cast<uint32_t>(RuleI(DynamicZone, WorldProcessRate)) }
|
|
{
|
|
}
|
|
|
|
void DynamicZoneManager::PurgeExpiredDynamicZones()
|
|
{
|
|
// purge when no members, instance is expired, or instance doesn't exist.
|
|
// this prevents characters remaining members of dzs that expired while
|
|
// server was offline but delayed instance purging hasn't cleaned yet
|
|
auto dz_ids = DynamicZonesRepository::GetStaleIDs(database);
|
|
|
|
if (!dz_ids.empty())
|
|
{
|
|
LogDynamicZones("Purging [{}] dynamic zone(s)", dz_ids.size());
|
|
|
|
DynamicZoneMembersRepository::DeleteWhere(database,
|
|
fmt::format("dynamic_zone_id IN ({})", fmt::join(dz_ids, ",")));
|
|
DynamicZonesRepository::DeleteWhere(database,
|
|
fmt::format("id IN ({})", fmt::join(dz_ids, ",")));
|
|
}
|
|
}
|
|
|
|
DynamicZone* DynamicZoneManager::CreateNew(
|
|
DynamicZone& dz_request, const std::vector<DynamicZoneMember>& members)
|
|
{
|
|
// this creates a new dz instance and saves it to both db and cache
|
|
uint32_t dz_id = dz_request.Create();
|
|
if (dz_id == 0)
|
|
{
|
|
LogDynamicZones("Failed to create dynamic zone for zone [{}]", dz_request.GetZoneID());
|
|
return nullptr;
|
|
}
|
|
|
|
auto dz = std::make_unique<DynamicZone>(dz_request);
|
|
if (!members.empty())
|
|
{
|
|
dz->SaveMembers(members);
|
|
dz->CacheMemberStatuses();
|
|
}
|
|
|
|
LogDynamicZones("Created new dz [{}] for zone [{}]", dz_id, dz_request.GetZoneID());
|
|
|
|
auto pack = dz->CreateServerDzCreatePacket(0, 0);
|
|
zoneserver_list.SendPacket(pack.get());
|
|
|
|
auto inserted = dynamic_zone_cache.emplace(dz_id, std::move(dz));
|
|
return inserted.first->second.get();
|
|
}
|
|
|
|
void DynamicZoneManager::CacheNewDynamicZone(ServerPacket* pack)
|
|
{
|
|
auto buf = reinterpret_cast<ServerDzCreateSerialized_Struct*>(pack->pBuffer);
|
|
|
|
auto new_dz = std::make_unique<DynamicZone>();
|
|
new_dz->LoadSerializedDzPacket(buf->cereal_data, buf->cereal_size);
|
|
new_dz->CacheMemberStatuses();
|
|
|
|
// reserialize with member statuses cached before forwarding (restore origin zone)
|
|
auto repack = new_dz->CreateServerDzCreatePacket(buf->origin_zone_id, buf->origin_instance_id);
|
|
|
|
uint32_t dz_id = new_dz->GetID();
|
|
dynamic_zone_cache.emplace(dz_id, std::move(new_dz));
|
|
LogDynamicZones("Cached new dynamic zone [{}]", dz_id);
|
|
|
|
zoneserver_list.SendPacket(repack.get());
|
|
}
|
|
|
|
void DynamicZoneManager::CacheAllFromDatabase()
|
|
{
|
|
BenchTimer bench;
|
|
|
|
auto dynamic_zones = DynamicZonesRepository::AllWithInstanceNotExpired(database);
|
|
auto dynamic_zone_members = DynamicZoneMembersRepository::GetAllWithNames(database);
|
|
|
|
dynamic_zone_cache.clear();
|
|
dynamic_zone_cache.reserve(dynamic_zones.size());
|
|
|
|
for (auto& entry : dynamic_zones)
|
|
{
|
|
uint32_t dz_id = entry.id;
|
|
auto dz = std::make_unique<DynamicZone>(std::move(entry));
|
|
|
|
for (auto& member : dynamic_zone_members)
|
|
{
|
|
if (member.dynamic_zone_id == dz_id)
|
|
{
|
|
dz->AddMemberFromRepositoryResult(std::move(member));
|
|
}
|
|
}
|
|
|
|
// note leader status won't be updated here until leader is set by owning system (expeditions)
|
|
dz->CacheMemberStatuses();
|
|
|
|
dynamic_zone_cache.emplace(dz_id, std::move(dz));
|
|
}
|
|
|
|
LogDynamicZones("Caching [{}] dynamic zone(s) took [{}s]", dynamic_zone_cache.size(), bench.elapsed());
|
|
}
|
|
|
|
void DynamicZoneManager::Process()
|
|
{
|
|
if (!m_process_throttle_timer.Check())
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::vector<uint32_t> dynamic_zone_ids;
|
|
|
|
for (const auto& dz_iter : dynamic_zone_cache)
|
|
{
|
|
DynamicZone* dz = dz_iter.second.get();
|
|
|
|
// dynamic zone is not deleted until its zone has no clients to prevent exploits
|
|
// clients should be removed by zone-based kick timers if expired but not empty
|
|
DynamicZoneStatus status = dz->Process();
|
|
if (status == DynamicZoneStatus::ExpiredEmpty)
|
|
{
|
|
LogDynamicZones("[{}] expired with [{}] members, notifying zones and deleting", dz->GetID(), dz->GetMemberCount());
|
|
dynamic_zone_ids.emplace_back(dz->GetID());
|
|
dz->SendZonesDynamicZoneDeleted(); // delete dz from zone caches
|
|
}
|
|
}
|
|
|
|
if (!dynamic_zone_ids.empty())
|
|
{
|
|
for (const auto& dz_id : dynamic_zone_ids)
|
|
{
|
|
dynamic_zone_cache.erase(dz_id);
|
|
}
|
|
|
|
// need to look up expedition ids until lockouts are moved to dynamic zones
|
|
std::vector<uint32_t> expedition_ids;
|
|
auto expeditions = ExpeditionsRepository::GetWhere(database,
|
|
fmt::format("dynamic_zone_id IN ({})", fmt::join(dynamic_zone_ids, ",")));
|
|
|
|
if (!expeditions.empty())
|
|
{
|
|
for (const auto& expedition : expeditions)
|
|
{
|
|
expedition_ids.emplace_back(expedition.id);
|
|
}
|
|
ExpeditionLockoutsRepository::DeleteWhere(database,
|
|
fmt::format("expedition_id IN ({})", fmt::join(expedition_ids, ",")));
|
|
}
|
|
|
|
ExpeditionsRepository::DeleteWhere(database,
|
|
fmt::format("dynamic_zone_id IN ({})", fmt::join(dynamic_zone_ids, ",")));
|
|
DynamicZoneMembersRepository::RemoveAllMembers(database, dynamic_zone_ids);
|
|
DynamicZonesRepository::DeleteWhere(database,
|
|
fmt::format("id IN ({})", fmt::join(dynamic_zone_ids, ",")));
|
|
}
|
|
}
|
|
|
|
void DynamicZoneManager::LoadTemplates()
|
|
{
|
|
m_dz_templates.clear();
|
|
auto dz_templates = DynamicZoneTemplatesRepository::All(content_db);
|
|
for (const auto& dz_template : dz_templates)
|
|
{
|
|
m_dz_templates[dz_template.id] = dz_template;
|
|
}
|
|
}
|