#include "dynamic_zone.h" #include "expedition.h" #include "expedition_state.h" #include "worlddb.h" #include "zonelist.h" #include "zoneserver.h" #include "../common/eqemu_logsys.h" #include "../common/repositories/instance_list_repository.h" extern ZSList zoneserver_list; DynamicZone::DynamicZone( uint32_t id, uint32_t zone_id, uint32_t instance_id, uint32_t zone_version, uint32_t start_time, uint32_t duration, DynamicZoneType type ) : m_id(id), m_instance_id(instance_id), m_zone_id(zone_id), m_zone_version(zone_version), m_start_time(std::chrono::system_clock::from_time_t(start_time)), m_duration(duration), m_type(type), m_expire_time(m_start_time + m_duration) { } DynamicZone* DynamicZone::FindDynamicZoneByID(uint32_t dz_id) { auto expedition = expedition_state.GetExpeditionByDynamicZoneID(dz_id); if (expedition) { return &expedition->GetDynamicZone(); } // todo: other system caches return nullptr; } void DynamicZone::SetSecondsRemaining(uint32_t seconds_remaining) { auto now = std::chrono::system_clock::now(); auto new_remaining = std::chrono::seconds(seconds_remaining); auto current_remaining = m_expire_time - now; if (current_remaining > new_remaining) // reduce only { LogDynamicZonesDetail("Updating dynamic zone [{}] instance [{}] seconds remaining to [{}]s", GetID(), GetInstanceID(), seconds_remaining); // preserve original start time and adjust duration instead m_expire_time = now + new_remaining; m_duration = std::chrono::duration_cast(m_expire_time - m_start_time); InstanceListRepository::UpdateDuration(database, GetInstanceID(), static_cast(m_duration.count())); SendZonesDurationUpdate(); // update zone caches and actual instance's timer } } void DynamicZone::SendZonesDurationUpdate() { constexpr uint32_t packsize = sizeof(ServerDzSetDuration_Struct); auto pack = std::make_unique(ServerOP_DzDurationUpdate, packsize); auto packbuf = reinterpret_cast(pack->pBuffer); packbuf->dz_id = GetID(); packbuf->seconds = static_cast(m_duration.count()); zoneserver_list.SendPacket(pack.get()); } void DynamicZone::HandleZoneMessage(ServerPacket* pack) { switch (pack->opcode) { case ServerOP_DzSetCompass: case ServerOP_DzSetSafeReturn: case ServerOP_DzSetZoneIn: { zoneserver_list.SendPacket(pack); break; } case ServerOP_DzCharacterChange: case ServerOP_DzRemoveAllCharacters: { auto buf = reinterpret_cast(pack->pBuffer); ZoneServer* instance_zs = zoneserver_list.FindByInstanceID(buf->instance_id); if (instance_zs) { instance_zs->SendPacket(pack); } break; } case ServerOP_DzSetSecondsRemaining: { auto buf = reinterpret_cast(pack->pBuffer); auto dz = DynamicZone::FindDynamicZoneByID(buf->dz_id); if (dz) { dz->SetSecondsRemaining(buf->seconds); } break; } }; }