mirror of
https://github.com/EQEmu/Server.git
synced 2026-01-09 16:33:53 +00:00
Let world shutdown dz early for empty expeditions
Since world now tracks empty expeditions it can determine when to shutdown dynamic zone instances when the rule is enabled rather than letting zones do it.
This commit is contained in:
parent
148af3edfc
commit
9164073d14
@ -160,6 +160,7 @@
|
||||
#define ServerOP_ExpeditionReplayOnJoin 0x0410
|
||||
#define ServerOP_ExpeditionLockState 0x0411
|
||||
#define ServerOP_ExpeditionMembersRemoved 0x0412
|
||||
#define ServerOP_ExpeditionDzDuration 0x0413
|
||||
|
||||
#define ServerOP_DzCharacterChange 0x0450
|
||||
#define ServerOP_DzRemoveAllCharacters 0x0451
|
||||
@ -2073,6 +2074,11 @@ struct ServerExpeditionCharacterID_Struct {
|
||||
uint32_t character_id;
|
||||
};
|
||||
|
||||
struct ServerExpeditionUpdateDuration_Struct {
|
||||
uint32_t expedition_id;
|
||||
uint32_t new_duration_seconds;
|
||||
};
|
||||
|
||||
struct ServerDzCommand_Struct {
|
||||
uint32 expedition_id;
|
||||
uint8 is_char_online; // 0: target name is offline, 1: online
|
||||
|
||||
@ -54,6 +54,42 @@ void Expedition::SendZonesExpeditionDeleted()
|
||||
zoneserver_list.SendPacket(pack.get());
|
||||
}
|
||||
|
||||
void Expedition::SendZonesDurationUpdate()
|
||||
{
|
||||
uint32_t packsize = sizeof(ServerExpeditionUpdateDuration_Struct);
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_ExpeditionDzDuration, packsize));
|
||||
auto packbuf = reinterpret_cast<ServerExpeditionUpdateDuration_Struct*>(pack->pBuffer);
|
||||
packbuf->expedition_id = GetID();
|
||||
packbuf->new_duration_seconds = m_duration;
|
||||
zoneserver_list.SendPacket(pack.get());
|
||||
}
|
||||
|
||||
void Expedition::UpdateDzSecondsRemaining(uint32_t seconds_remaining)
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto update_time = std::chrono::seconds(seconds_remaining);
|
||||
|
||||
auto current_remaining = m_expire_time - now;
|
||||
if (current_remaining > update_time) // reduce only
|
||||
{
|
||||
LogExpeditionsDetail(
|
||||
"Updating expedition [{}] dz instance [{}] seconds remaining to [{}]s",
|
||||
GetID(), GetInstanceID(), seconds_remaining
|
||||
);
|
||||
|
||||
// preserve original start time and adjust duration instead
|
||||
auto new_expire_time = now + update_time;
|
||||
auto new_duration = std::chrono::system_clock::to_time_t(new_expire_time) - m_start_time;
|
||||
m_duration = static_cast<uint32_t>(new_duration);
|
||||
m_expire_time = std::chrono::system_clock::from_time_t(m_start_time + m_duration);
|
||||
|
||||
ExpeditionDatabase::UpdateDzDuration(GetInstanceID(), m_duration);
|
||||
|
||||
// update zone level caches and update the actual dz instance's timer
|
||||
SendZonesDurationUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionCache::LoadActiveExpeditions()
|
||||
{
|
||||
BenchTimer benchmark;
|
||||
@ -151,6 +187,13 @@ void ExpeditionCache::Process()
|
||||
it->SendZonesExpeditionDeleted();
|
||||
is_deleted = true;
|
||||
}
|
||||
|
||||
if (it->IsEmpty() && !it->IsPendingDelete() && RuleB(Expedition, EmptyDzShutdownEnabled))
|
||||
{
|
||||
it->UpdateDzSecondsRemaining(RuleI(Expedition, EmptyDzShutdownDelaySeconds));
|
||||
}
|
||||
|
||||
it->SetPendingDelete(true);
|
||||
}
|
||||
|
||||
it = is_deleted ? m_expeditions.erase(it) : it + 1;
|
||||
@ -334,6 +377,16 @@ void ExpeditionDatabase::DeleteExpeditions(const std::vector<uint32_t>& expediti
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@ -39,6 +39,7 @@ namespace ExpeditionDatabase
|
||||
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
|
||||
@ -82,7 +83,11 @@ public:
|
||||
uint16_t GetZoneID() const { return static_cast<uint16_t>(m_dz_zone_id); }
|
||||
bool IsEmpty() const { return m_member_ids.empty(); }
|
||||
bool IsExpired() const { return m_expire_time < std::chrono::system_clock::now(); }
|
||||
bool IsPendingDelete() const { return m_pending_delete; }
|
||||
void SendZonesDurationUpdate();
|
||||
void SendZonesExpeditionDeleted();
|
||||
void SetPendingDelete(bool pending) { m_pending_delete = pending; }
|
||||
void UpdateDzSecondsRemaining(uint32_t seconds_remaining);
|
||||
|
||||
private:
|
||||
uint32_t m_expedition_id = 0;
|
||||
@ -90,6 +95,7 @@ private:
|
||||
uint32_t m_dz_zone_id = 0;
|
||||
uint32_t m_start_time = 0;
|
||||
uint32_t m_duration = 0;
|
||||
bool m_pending_delete = false;
|
||||
std::unordered_set<uint32_t> m_member_ids;
|
||||
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
|
||||
};
|
||||
|
||||
@ -437,32 +437,6 @@ void DynamicZone::SendInstanceCharacterChange(uint32_t character_id, bool remove
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::UpdateExpireTime(uint32_t seconds, bool reduce_only)
|
||||
{
|
||||
if (GetInstanceID() == 0 || (reduce_only && GetSecondsRemaining() < seconds))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_expire_time = std::chrono::system_clock::now() + std::chrono::seconds(seconds);
|
||||
m_duration = std::chrono::system_clock::to_time_t(m_expire_time) - m_start_time;
|
||||
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE instance_list SET duration = {} WHERE id = {};
|
||||
), m_duration, GetInstanceID());
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
{
|
||||
uint32_t packsize = sizeof(ServerInstanceUpdateTime_Struct);
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_InstanceUpdateTime, packsize));
|
||||
auto packbuf = reinterpret_cast<ServerInstanceUpdateTime_Struct*>(pack->pBuffer);
|
||||
packbuf->instance_id = GetInstanceID();
|
||||
packbuf->new_duration = seconds;
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SetCompass(const DynamicZoneLocation& location, bool update_db)
|
||||
{
|
||||
m_compass = location;
|
||||
@ -515,6 +489,18 @@ uint32_t DynamicZone::GetSecondsRemaining() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DynamicZone::SetUpdatedDuration(uint32_t new_duration)
|
||||
{
|
||||
// preserves original start time, just modifies duration and expire time
|
||||
m_duration = new_duration;
|
||||
m_expire_time = std::chrono::system_clock::from_time_t(m_start_time + m_duration);
|
||||
|
||||
if (zone && IsCurrentZoneDzInstance())
|
||||
{
|
||||
zone->SetInstanceTimer(GetSecondsRemaining());
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::HandleWorldMessage(ServerPacket* pack)
|
||||
{
|
||||
switch (pack->opcode)
|
||||
|
||||
@ -89,7 +89,7 @@ public:
|
||||
void SetCompass(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void SetSafeReturn(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void UpdateExpireTime(uint32_t seconds, bool reduce_only = true);
|
||||
void SetUpdatedDuration(uint32_t seconds);
|
||||
|
||||
void LoadFromDatabase(uint32_t instance_id);
|
||||
uint32_t SaveToDatabase();
|
||||
|
||||
@ -477,15 +477,10 @@ bool Expedition::AddMember(const std::string& add_char_name, uint32_t add_char_i
|
||||
return true;
|
||||
}
|
||||
|
||||
void Expedition::RemoveAllMembers(bool enable_removal_timers, bool update_dz_expire_time)
|
||||
void Expedition::RemoveAllMembers(bool enable_removal_timers)
|
||||
{
|
||||
m_dynamiczone.RemoveAllCharacters(enable_removal_timers);
|
||||
|
||||
if (update_dz_expire_time && RuleB(Expedition, EmptyDzShutdownEnabled))
|
||||
{
|
||||
m_dynamiczone.UpdateExpireTime(RuleI(Expedition, EmptyDzShutdownDelaySeconds));
|
||||
}
|
||||
|
||||
ExpeditionDatabase::UpdateAllMembersRemoved(m_id);
|
||||
|
||||
SendUpdatesToZoneMembers(true);
|
||||
@ -512,18 +507,6 @@ bool Expedition::RemoveMember(const std::string& remove_char_name)
|
||||
ChooseNewLeader();
|
||||
}
|
||||
|
||||
// we can't check for empty member count via cache because if other zones
|
||||
// remove members at the same time then we race. cache member count won't
|
||||
// be accurate until the world messages from other zones are processed
|
||||
uint32_t member_count = ExpeditionDatabase::GetExpeditionMemberCount(m_id);
|
||||
if (member_count == 0)
|
||||
{
|
||||
if (RuleB(Expedition, EmptyDzShutdownEnabled))
|
||||
{
|
||||
m_dynamiczone.UpdateExpireTime(RuleI(Expedition, EmptyDzShutdownDelaySeconds));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1813,6 +1796,16 @@ void Expedition::HandleWorldMessage(ServerPacket* pack)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionDzDuration:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerExpeditionUpdateDuration_Struct*>(pack->pBuffer);
|
||||
auto expedition = Expedition::FindCachedExpeditionByID(buf->expedition_id);
|
||||
if (expedition)
|
||||
{
|
||||
expedition->SetDzDuration(buf->new_duration_seconds);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -102,7 +102,7 @@ public:
|
||||
bool AddMember(const std::string& add_char_name, uint32_t add_char_id);
|
||||
bool HasMember(const std::string& character_name);
|
||||
bool HasMember(uint32_t character_id);
|
||||
void RemoveAllMembers(bool enable_removal_timers = true, bool update_dz_expire_time = true);
|
||||
void RemoveAllMembers(bool enable_removal_timers = true);
|
||||
bool RemoveMember(const std::string& remove_char_name);
|
||||
void SetMemberStatus(Client* client, ExpeditionMemberStatus status);
|
||||
void SetNewLeader(uint32_t new_leader_id, const std::string& new_leader_name);
|
||||
@ -134,6 +134,7 @@ public:
|
||||
void SetDzSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db = false);
|
||||
void SetDzSafeReturn(const std::string& zone_name, float x, float y, float z, float heading, bool update_db = false);
|
||||
void SetDzZoneInLocation(float x, float y, float z, float heading, bool update_db = false);
|
||||
void SetDzDuration(uint32_t new_duration) { m_dynamiczone.SetUpdatedDuration(new_duration); }
|
||||
|
||||
static const uint32_t REPLAY_TIMER_ID;
|
||||
static const uint32_t EVENT_TIMER_ID;
|
||||
|
||||
@ -395,25 +395,6 @@ ExpeditionMember ExpeditionDatabase::GetExpeditionLeader(uint32_t expedition_id)
|
||||
return leader;
|
||||
}
|
||||
|
||||
uint32_t ExpeditionDatabase::GetExpeditionMemberCount(uint32_t expedition_id)
|
||||
{
|
||||
auto query = fmt::format(SQL(
|
||||
SELECT COUNT(IF(is_current_member = TRUE, 1, NULL)) member_count
|
||||
FROM expedition_members
|
||||
WHERE expedition_id = {};
|
||||
), expedition_id);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
uint32_t member_count = 0;
|
||||
if (results.Success() && results.RowCount() > 0)
|
||||
{
|
||||
auto row = results.begin();
|
||||
member_count = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
|
||||
}
|
||||
return member_count;
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::InsertCharacterLockouts(
|
||||
uint32_t character_id, const std::vector<ExpeditionLockoutTimer>& lockouts,
|
||||
bool update_expire_times, bool is_pending)
|
||||
|
||||
@ -55,7 +55,6 @@ namespace ExpeditionDatabase
|
||||
uint32_t GetExpeditionIDFromCharacterID(uint32_t character_id);
|
||||
uint32_t GetExpeditionIDFromInstanceID(uint32_t instance_id);
|
||||
ExpeditionMember GetExpeditionLeader(uint32_t expedition_id);
|
||||
uint32_t GetExpeditionMemberCount(uint32_t expedition_id);
|
||||
void InsertCharacterLockouts(
|
||||
uint32_t character_id, const std::vector<ExpeditionLockoutTimer>& lockouts,
|
||||
bool update_expire_times, bool is_pending = false);
|
||||
|
||||
@ -2915,6 +2915,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
case ServerOP_ExpeditionDzCompass:
|
||||
case ServerOP_ExpeditionDzSafeReturn:
|
||||
case ServerOP_ExpeditionDzZoneIn:
|
||||
case ServerOP_ExpeditionDzDuration:
|
||||
case ServerOP_ExpeditionRemoveCharLockouts:
|
||||
{
|
||||
Expedition::HandleWorldMessage(pack);
|
||||
|
||||
@ -1495,7 +1495,7 @@ bool Zone::Process() {
|
||||
Expedition* expedition = Expedition::FindExpeditionByInstanceID(GetInstanceID());
|
||||
if (expedition)
|
||||
{
|
||||
expedition->RemoveAllMembers(false, false); // entity list will teleport clients out immediately
|
||||
expedition->RemoveAllMembers(false); // entity list will teleport clients out immediately
|
||||
}
|
||||
// todo: move corpses to non-instanced version of dz at same coords (if no graveyard)
|
||||
entity_list.GateAllClientsToSafeReturn();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user