mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 01:11:29 +00:00
[Expeditions] Let dz process its expired state (#1310)
Move early empty shutdown and process rate rules to DynamicZone scope This decouples the expired status check from expeditions into an internal dz method that can be called by its owning system
This commit is contained in:
parent
97c11a1199
commit
f5cf566fca
@ -736,9 +736,6 @@ RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Expedition)
|
||||
RULE_INT(Expedition, MinStatusToBypassPlayerCountRequirements, 80, "Minimum GM status to bypass minimum player requirements for Expedition creation")
|
||||
RULE_BOOL(Expedition, EmptyDzShutdownEnabled, true, "Enable early instance shutdown after last member of expedition removed")
|
||||
RULE_INT(Expedition, EmptyDzShutdownDelaySeconds, 1500, "Seconds to set dynamic zone instance expiration if early shutdown enabled")
|
||||
RULE_INT(Expedition, WorldExpeditionProcessRateMS, 6000, "Timer interval (milliseconds) that world checks expedition states")
|
||||
RULE_BOOL(Expedition, AlwaysNotifyNewLeaderOnChange, false, "Always notify clients when made expedition leader. If false (live-like) new leaders are only notified when made leader via /dzmakeleader")
|
||||
RULE_REAL(Expedition, LockoutDurationMultiplier, 1.0, "Multiplies lockout duration by this value when new lockouts are added")
|
||||
RULE_BOOL(Expedition, EnableInDynamicZoneStatus, false, "Enables the 'In Dynamic Zone' member status in expedition window. If false (live-like) players inside the dynamic zone will show as 'Online'")
|
||||
@ -747,6 +744,9 @@ RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(DynamicZone)
|
||||
RULE_INT(DynamicZone, ClientRemovalDelayMS, 60000, "Delay (milliseconds) until a client is teleported out of dynamic zone after being removed as member")
|
||||
RULE_BOOL(DynamicZone, EmptyShutdownEnabled, true, "Enable early instance shutdown for dynamic zones that have no members")
|
||||
RULE_INT(DynamicZone, EmptyShutdownDelaySeconds, 1500, "Seconds to set dynamic zone instance expiration if early shutdown enabled")
|
||||
RULE_INT(DynamicZone, WorldProcessRate, 6000, "Timer interval (milliseconds) that systems check their dynamic zone states")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
#undef RULE_CATEGORY
|
||||
|
||||
@ -35,6 +35,30 @@ DynamicZone* DynamicZone::FindDynamicZoneByID(uint32_t dz_id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DynamicZoneStatus DynamicZone::Process(bool force_expire)
|
||||
{
|
||||
DynamicZoneStatus status = DynamicZoneStatus::Normal;
|
||||
|
||||
if (force_expire || IsExpired())
|
||||
{
|
||||
status = DynamicZoneStatus::Expired;
|
||||
|
||||
auto dz_zoneserver = zoneserver_list.FindByInstanceID(GetInstanceID());
|
||||
if (!dz_zoneserver || dz_zoneserver->NumPlayers() == 0) // no clients inside dz
|
||||
{
|
||||
status = DynamicZoneStatus::ExpiredEmpty;
|
||||
|
||||
if (force_expire && !m_is_pending_early_shutdown && RuleB(DynamicZone, EmptyShutdownEnabled))
|
||||
{
|
||||
SetSecondsRemaining(RuleI(DynamicZone, EmptyShutdownDelaySeconds));
|
||||
m_is_pending_early_shutdown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void DynamicZone::SetSecondsRemaining(uint32_t seconds_remaining)
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
|
||||
@ -6,6 +6,14 @@
|
||||
|
||||
class ServerPacket;
|
||||
|
||||
enum class DynamicZoneStatus
|
||||
{
|
||||
Unknown = 0,
|
||||
Normal,
|
||||
Expired,
|
||||
ExpiredEmpty,
|
||||
};
|
||||
|
||||
class DynamicZone
|
||||
{
|
||||
public:
|
||||
@ -23,6 +31,7 @@ public:
|
||||
std::chrono::system_clock::duration GetRemainingDuration() const {
|
||||
return m_expire_time - std::chrono::system_clock::now(); }
|
||||
|
||||
DynamicZoneStatus Process(bool force_expire);
|
||||
bool IsExpired() const { return m_expire_time < std::chrono::system_clock::now(); }
|
||||
void SetSecondsRemaining(uint32_t seconds_remaining);
|
||||
|
||||
@ -33,6 +42,7 @@ private:
|
||||
uint32_t m_instance_id = 0;
|
||||
uint32_t m_zone_id = 0;
|
||||
uint32_t m_zone_version = 0;
|
||||
bool m_is_pending_early_shutdown = false;
|
||||
DynamicZoneType m_type{ DynamicZoneType::None };
|
||||
std::chrono::seconds m_duration;
|
||||
std::chrono::time_point<std::chrono::system_clock> m_start_time;
|
||||
|
||||
@ -161,3 +161,21 @@ void Expedition::CheckLeader()
|
||||
ChooseNewLeader();
|
||||
}
|
||||
}
|
||||
|
||||
bool Expedition::Process()
|
||||
{
|
||||
// returns true if expedition needs to be deleted from world cache and db
|
||||
// expedition is not deleted until its dz has no clients to prevent exploits
|
||||
auto status = m_dynamic_zone.Process(IsEmpty()); // force expire if no members
|
||||
if (status == DynamicZoneStatus::ExpiredEmpty)
|
||||
{
|
||||
LogExpeditions("Expedition [{}] expired or empty, notifying zones and deleting", GetID());
|
||||
SendZonesExpeditionDeleted();
|
||||
return true;
|
||||
}
|
||||
|
||||
CheckExpireWarning();
|
||||
CheckLeader();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -43,19 +43,17 @@ public:
|
||||
uint32_t GetID() const { return m_expedition_id; }
|
||||
bool HasMember(uint32_t character_id);
|
||||
bool IsEmpty() const { return m_member_ids.empty(); }
|
||||
bool IsPendingDelete() const { return m_pending_delete; }
|
||||
bool IsValid() const { return m_expedition_id != 0; }
|
||||
bool Process();
|
||||
void SendZonesExpeditionDeleted();
|
||||
void SendZonesExpireWarning(uint32_t minutes_remaining);
|
||||
bool SetNewLeader(uint32_t new_leader_id);
|
||||
void SetPendingDelete(bool pending) { m_pending_delete = pending; }
|
||||
|
||||
private:
|
||||
void SendZonesLeaderChanged();
|
||||
|
||||
uint32_t m_expedition_id = 0;
|
||||
uint32_t m_leader_id = 0;
|
||||
bool m_pending_delete = false;
|
||||
bool m_choose_leader_needed = false;
|
||||
Timer m_choose_leader_cooldown_timer;
|
||||
Timer m_warning_cooldown_timer;
|
||||
|
||||
@ -21,13 +21,9 @@
|
||||
#include "expedition_state.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;
|
||||
|
||||
ExpeditionState expedition_state;
|
||||
|
||||
Expedition* ExpeditionState::GetExpedition(uint32_t expedition_id)
|
||||
@ -117,36 +113,11 @@ void ExpeditionState::Process()
|
||||
|
||||
for (auto it = m_expeditions.begin(); it != m_expeditions.end();)
|
||||
{
|
||||
bool is_deleted = false;
|
||||
|
||||
if (it->IsEmpty() || it->GetDynamicZone().IsExpired())
|
||||
bool is_deleted = it->Process();
|
||||
if (is_deleted)
|
||||
{
|
||||
// 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->GetDynamicZone().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->GetDynamicZone().SetSecondsRemaining(RuleI(Expedition, EmptyDzShutdownDelaySeconds));
|
||||
}
|
||||
|
||||
it->SetPendingDelete(true);
|
||||
expedition_ids.emplace_back(it->GetID());
|
||||
}
|
||||
else
|
||||
{
|
||||
it->CheckExpireWarning();
|
||||
it->CheckLeader();
|
||||
}
|
||||
|
||||
it = is_deleted ? m_expeditions.erase(it) : it + 1;
|
||||
}
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ public:
|
||||
|
||||
private:
|
||||
std::vector<Expedition> m_expeditions;
|
||||
Timer m_process_throttle_timer{static_cast<uint32_t>(RuleI(Expedition, WorldExpeditionProcessRateMS))};
|
||||
Timer m_process_throttle_timer{static_cast<uint32_t>(RuleI(DynamicZone, WorldProcessRate))};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user