mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 12:41:30 +00:00
[DynamicZones] Bulk request dz member statuses on zone boot (#4769)
When dynamic zones are cached on zone boot each dz requests member statuses from world separately. This causes a lot of network traffic between world and booted zones when there are a lot of active dzs. This changes it to make a single request to world on zone boot and a single bulk reply back.
This commit is contained in:
parent
84708edccf
commit
051ce3736f
@ -196,6 +196,7 @@
|
||||
#define ServerOP_DzSaveInvite 0x0466
|
||||
#define ServerOP_DzRequestInvite 0x0467
|
||||
#define ServerOP_DzMakeLeader 0x0468
|
||||
#define ServerOP_DzGetBulkMemberStatuses 0x0469
|
||||
|
||||
#define ServerOP_LSInfo 0x1000
|
||||
#define ServerOP_LSStatus 0x1001
|
||||
@ -1555,6 +1556,13 @@ struct ServerDzMemberStatuses_Struct {
|
||||
ServerDzMemberStatusEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct ServerDzCerealData_Struct {
|
||||
uint16_t zone_id;
|
||||
uint16_t inst_id;
|
||||
uint32_t cereal_size;
|
||||
char cereal_data[1];
|
||||
};
|
||||
|
||||
struct ServerDzMovePC_Struct {
|
||||
uint32 dz_id;
|
||||
uint16 sender_zone_id;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "zoneserver.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/repositories/dynamic_zone_lockouts_repository.h"
|
||||
#include <cereal/types/utility.hpp>
|
||||
|
||||
extern ClientList client_list;
|
||||
extern ZSList zoneserver_list;
|
||||
@ -169,6 +170,33 @@ void DynamicZoneManager::LoadTemplates()
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZoneManager::SendBulkMemberStatuses(uint32_t zone_id, uint16_t inst_id)
|
||||
{
|
||||
std::vector<std::pair<uint32_t, std::vector<DynamicZoneMember>>> dzs;
|
||||
dzs.reserve(dynamic_zone_cache.size());
|
||||
|
||||
for (const auto& [dz_id, dz] : dynamic_zone_cache)
|
||||
{
|
||||
dzs.emplace_back(dz_id, dz->GetMembers());
|
||||
}
|
||||
|
||||
std::ostringstream ss;
|
||||
{
|
||||
cereal::BinaryOutputArchive archive(ss);
|
||||
archive(dzs);
|
||||
}
|
||||
|
||||
std::string_view sv = ss.view();
|
||||
|
||||
size_t size = sizeof(ServerDzCerealData_Struct) + sv.size();
|
||||
ServerPacket pack(ServerOP_DzGetBulkMemberStatuses, static_cast<uint32_t>(size));
|
||||
auto buf = reinterpret_cast<ServerDzCerealData_Struct*>(pack.pBuffer);
|
||||
buf->cereal_size = static_cast<uint32_t>(sv.size());
|
||||
memcpy(buf->cereal_data, sv.data(), sv.size());
|
||||
|
||||
zoneserver_list.SendPacket(zone_id, inst_id, &pack);
|
||||
}
|
||||
|
||||
void DynamicZoneManager::HandleZoneMessage(ServerPacket* pack)
|
||||
{
|
||||
switch (pack->opcode)
|
||||
@ -338,6 +366,15 @@ void DynamicZoneManager::HandleZoneMessage(ServerPacket* pack)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_DzGetBulkMemberStatuses:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzCerealData_Struct*>(pack->pBuffer);
|
||||
if (buf->zone_id != 0 && !dynamic_zone_cache.empty())
|
||||
{
|
||||
SendBulkMemberStatuses(buf->zone_id, buf->inst_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_DzUpdateMemberStatus:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzMemberStatus_Struct*>(pack->pBuffer);
|
||||
|
||||
@ -30,6 +30,8 @@ public:
|
||||
std::unordered_map<uint32_t, std::unique_ptr<DynamicZone>> dynamic_zone_cache;
|
||||
|
||||
private:
|
||||
void SendBulkMemberStatuses(uint32_t zone_id, uint16_t inst_id);
|
||||
|
||||
Timer m_process_throttle_timer{};
|
||||
std::unordered_map<uint32_t, DynamicZoneTemplatesRepository::DynamicZoneTemplates> m_dz_templates;
|
||||
};
|
||||
|
||||
@ -1480,6 +1480,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
case ServerOP_DzSwapMembers:
|
||||
case ServerOP_DzRemoveAllMembers:
|
||||
case ServerOP_DzGetMemberStatuses:
|
||||
case ServerOP_DzGetBulkMemberStatuses:
|
||||
case ServerOP_DzSetSecondsRemaining:
|
||||
case ServerOP_DzSetCompass:
|
||||
case ServerOP_DzSetSafeReturn:
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "worldserver.h"
|
||||
#include "../common/repositories/character_expedition_lockouts_repository.h"
|
||||
#include "../common/repositories/dynamic_zone_lockouts_repository.h"
|
||||
#include <cereal/types/utility.hpp>
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
@ -162,14 +163,28 @@ void DynamicZone::CacheAllFromDatabase()
|
||||
}
|
||||
}
|
||||
|
||||
dz->UpdateMembers();
|
||||
zone->dynamic_zone_cache.emplace(dz_id, std::move(dz));
|
||||
}
|
||||
|
||||
if (!zone->dynamic_zone_cache.empty())
|
||||
{
|
||||
RequestMemberStatuses();
|
||||
}
|
||||
|
||||
LogInfo("Loaded [{}] dynamic zone(s)", Strings::Commify(zone->dynamic_zone_cache.size()));
|
||||
LogDynamicZones("Caching [{}] dynamic zone(s) took [{}s]", zone->dynamic_zone_cache.size(), bench.elapsed());
|
||||
}
|
||||
|
||||
void DynamicZone::RequestMemberStatuses()
|
||||
{
|
||||
ServerPacket pack(ServerOP_DzGetBulkMemberStatuses, sizeof(ServerDzCerealData_Struct));
|
||||
auto buf = reinterpret_cast<ServerDzCerealData_Struct*>(pack.pBuffer);
|
||||
buf->zone_id = static_cast<uint16_t>(zone->GetZoneID());
|
||||
buf->inst_id = static_cast<uint16_t>(zone->GetInstanceID());
|
||||
|
||||
worldserver.SendPacket(&pack);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DynamicZone* FindDynamicZone(T pred)
|
||||
{
|
||||
@ -849,6 +864,34 @@ void DynamicZone::HandleWorldMessage(ServerPacket* pack)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_DzGetBulkMemberStatuses:
|
||||
{
|
||||
if (zone)
|
||||
{
|
||||
std::vector<std::pair<uint32_t, std::vector<DynamicZoneMember>>> dzs;
|
||||
dzs.reserve(zone->dynamic_zone_cache.size());
|
||||
|
||||
auto buf = reinterpret_cast<ServerDzCerealData_Struct*>(pack->pBuffer);
|
||||
EQ::Util::MemoryStreamReader ss(buf->cereal_data, buf->cereal_size);
|
||||
{
|
||||
cereal::BinaryInputArchive archive(ss);
|
||||
archive(dzs);
|
||||
}
|
||||
|
||||
for (const auto& [dz_id, members] : dzs)
|
||||
{
|
||||
if (auto dz = DynamicZone::FindDynamicZoneByID(dz_id))
|
||||
{
|
||||
for (const auto& member : members)
|
||||
{
|
||||
dz->SetInternalMemberStatus(member.id, member.status);
|
||||
}
|
||||
dz->m_has_member_statuses = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_DzUpdateMemberStatus:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzMemberStatus_Struct*>(pack->pBuffer);
|
||||
|
||||
@ -92,13 +92,13 @@ public:
|
||||
void SendMemberNameToZoneMembers(const std::string& char_name, bool remove);
|
||||
void SendMemberStatusToZoneMembers(const DynamicZoneMember& member);
|
||||
void SetLocked(bool lock, bool update_db = false, DzLockMsg lock_msg = DzLockMsg::None, uint32_t color = Chat::Yellow);
|
||||
void UpdateMembers();
|
||||
|
||||
std::string GetLootEvent(uint32_t id, DzLootEvent::Type type) const;
|
||||
void SetLootEvent(uint32_t id, const std::string& event, DzLootEvent::Type type);
|
||||
|
||||
private:
|
||||
static void StartAllClientRemovalTimers();
|
||||
static void RequestMemberStatuses();
|
||||
|
||||
uint16_t GetCurrentInstanceID() const override;
|
||||
uint16_t GetCurrentZoneID() const override;
|
||||
@ -125,6 +125,7 @@ private:
|
||||
void SendWorldPlayerInvite(const std::string& inviter, const std::string& swap_name, const std::string& add_name, bool pending = false);
|
||||
void SetUpdatedDuration(uint32_t seconds);
|
||||
void TryAddClient(Client* add_client, const std::string& inviter, const std::string& swap_name, Client* leader = nullptr);
|
||||
void UpdateMembers();
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> CreateExpireWarningPacket(uint32_t minutes_remaining);
|
||||
std::unique_ptr<EQApplicationPacket> CreateInfoPacket(bool clear = false);
|
||||
|
||||
@ -3410,6 +3410,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
case ServerOP_DzRemoveAllMembers:
|
||||
case ServerOP_DzDurationUpdate:
|
||||
case ServerOP_DzGetMemberStatuses:
|
||||
case ServerOP_DzGetBulkMemberStatuses:
|
||||
case ServerOP_DzSetCompass:
|
||||
case ServerOP_DzSetSafeReturn:
|
||||
case ServerOP_DzSetZoneIn:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user